> For the complete documentation index, see [llms.txt](https://lochiwei.gitbook.io/ios/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://lochiwei.gitbook.io/ios/swift/debugging/hasmirrors.md).

# HasMirrors

{% tabs %}
{% tab title="👔 HasMirrors" %}
💾 程式：[replit](https://replit.com/@pegasusroe/Swift-Playground#Logs/Loggable.swift)    ⬆️ 需要：[Mirror](/ios/swift/debugging/mirror.md), [Logger](/ios/swift/debugging/logger.md)

```swift
// ────────────────────────────────────────────────────────────
// 2022.01.27 * v.1 + log, reflect, mirror
// 2022.01.28 / log, reflect, mirrorChildren: use `Logger`
//            - rename `item` as `HasMirrors`
//            + default conformances: Int, Double
//            + extend [HasMirrors]: `items.log()`
//            + Bool.log(): custom conformance
// ────────────────────────────────────────────────────────────

// ┌──────────────────┐
// │    HasMirrors    │
// └──────────────────┘

public protocol HasMirrors {
    /// `item.log()`
    func log() -> Self              // for chaining
    /// `item.reflect()`
    func reflect() -> Self          // for chaining
    /// `item.mirror()`
    func mirror() -> Self           // for chaining
}

// ⭐ default behaviors
extension HasMirrors {

    /// `item.log()`
    @discardableResult
    public func log() -> Self { 
        Logger.log(String(describing: self), dot: "🍄")
        return self 
    }
    
    /// `item.reflect()`
    @discardableResult
    public func reflect() -> Self { 
        Logger.log(String(reflecting: self), dot: "🍄")
        return self 
    }
    
    // mirrorChildren (object tree)
    @discardableResult
    func mirrorChildren<T>(of subject: T) -> Self {
    
        let title = "\(String(describing: subject))"
        Logger.box(title)
        
        
        // ⭐ mirror children
        let children = Mirror(reflecting: subject).children
        if children.count == 0 { print("  // no children") }
        
        children.forEach { child in
            let label = "\(child.label ?? "_")"
            let value = " \(child.value)"
            let valueType = " (\(type(of: child.value)))"
            Logger.log(label + ":" + value + valueType, dot: "🔸")
        }
        
        Logger.line(title.count + 10)
        return self
    }
    
    /// `item.mirror()`
    @discardableResult
    public func mirror() -> Self {
        return mirrorChildren(of: self)
    }
}

// ┌──────────────────────────────┐
// │    [HasMirrors] extension    │
// └──────────────────────────────┘

extension Array where Element == HasMirrors {
    /// `items.log()`
    @discardableResult
    public func log() -> Array { 
        self.forEach { _ = $0.log() }  // _: silence compiler warning.
        return self 
    }
}

// ┌────────────────────────────┐
// │    default conformances    │
// └────────────────────────────┘

extension String: HasMirrors {}
extension Int   : HasMirrors {}
extension Double: HasMirrors {}

extension Bool  : HasMirrors {
    public func log() -> Bool {
        Logger.log(self ? "✅" : "❌")
        return self
    }
}
```

{% endtab %}

{% tab title="💈範例" %}
💾 程式： [replit](https://replit.com/@pegasusroe/Swift-Playground#test/testHasMirrors.swift)

```swift
struct Person: HasMirrors {
    let name: String
    let age : Int
}

func testHasMirrors() {
    let joe = Person(name: "Joe", age: 8)
    joe.log().reflect().mirror()
}
```

#### Result:

```swift
// 🍄 Person(name: "Joe", age: 8)
// 🍄 main.Person(name: "Joe", age: 8)
// ┌───────────────────────────────────┐
// │    Person(name: "Joe", age: 8)    │
// └───────────────────────────────────┘
// 🔸 name: Joe (String)
// 🔸 age: 8 (Int)
// ─────────────────────────────────────
```

{% endtab %}

{% tab title="📗 參考" %}

* [ ] Sarun ⟩ [What is @discardableResult](https://sarunw.com/posts/what-is-discardableresult/)
  {% endtab %}

{% tab title="⬇️ 應用" %}

* [CaseReflectable](/ios/swift/debugging/casereflectable.md) (<mark style="color:red;">**protocol**</mark>) - inherits from Loggable.
* [NonNominalTypeWrapper](/ios/swift/debugging/nonnominaltypewrapper.md) (<mark style="color:red;">**struct**</mark>) - conforms to Loggable.
  {% endtab %}

{% tab title="👥 相關" %}

* uses [Mirror](/ios/swift/debugging/mirror.md).
* uses [Logger](/ios/swift/debugging/logger.md).
* used by [log()](/ios/swift/debugging/log.md).
* [.logType()](/ios/swiftui/view/view/view.md)
  {% endtab %}
  {% endtabs %}

## History

{% tabs %}
{% tab title="contents" %}

1. (2022.01.27) - original post
   {% endtab %}

{% tab title="1" %}
💾 程式：[paiza.io](https://paiza.io/projects/BgeXldbalSZcvt3C_5qcQg)    ⬆️ 需要：[Mirror](/ios/swift/debugging/mirror.md)

```swift
// 2022.01.27 * first version

// -------------------
//     ⭐ Loggable
// -------------------

public protocol Loggable {
    /// show `String(describing: self)` by default
    func log() -> Self
    /// show `String(reflecting: self)` by default
    func reflect() -> Self
    /// show `Mirror(reflecting: self).children` by default
    func mirror() -> Self
}

// ⭐ default behaviors
extension Loggable {

    @discardableResult
    public func log() -> Self { print(String(describing: self)) ; return self }
    
    @discardableResult
    public func reflect() -> Self { print(String(reflecting: self)) ; return self }
    
    // mirrorChildren (object tree)
    @discardableResult
    func mirrorChildren<T>(of subject: T) -> Self {
    
        let selfDesc = "    children of \(String(describing: subject))    "
        let line = String(repeating: "-", count: selfDesc.count)
        
        print()
        print(line)
        print("\(selfDesc)")
        print(line)
        
        // ⭐ mirror children
        let children = Mirror(reflecting: subject).children
        if children.count == 0 { print("  // no children") }
        
        children.forEach { child in
            print("  • \(child.label ?? "_"): \(child.value) (\(type(of: child.value)))")
        }
        
        print(line)
        print()
        
        return self
    }
    
    @discardableResult
    public func mirror() -> Self {
        mirrorChildren(of: self)
    }
}
```

{% endtab %}
{% endtabs %}
