Protocol
CustomDumpReflectable
public protocol CustomDumpReflectable
A type that explicitly supplies its own mirror for customDump(_:to:name:indent:maxDepth:)
and diff(_:_:format:)
.
Types that want to customize their dump output can conform to this protocol, especially those with a complex or nested internal structure. Providing a custom mirror allows you to reorder, transform, or omit fields on a base structure, or even change the representation of the base structure itself.
For unstructured data types, or data types that are represented by single values, see the
CustomDumpStringConvertible
protocol.
Customizing the dump of a structure's fields
For example, let's say you have a struct representing login state, which holds a secure token in
memory that should never be written to your logs. You can omit the token from customDump
by
providing a mirror that omits this field:
struct LoginState: CustomDumpReflectable {
var email = ""
var password = ""
var token: String
var customDumpMirror: Mirror {
.init(
self,
children: [
"email": self.email,
"password": self.password
// omit token from logs
],
displayStyle: .struct
)
}
}
customDump(
LoginState(
email: "blob@pointfree.co",
password: "bl0bisawesome!",
token: "secret"
)
)
LoginState(
email: "blob@pointfree.co",
password: "bl0bisawesome!"
)
There! No token data is being written to the dump. However, the dump still contains the user's
password, which is sensitive. Rather than omit it entirely, we could redact this information
using a Redacted
wrapper type that redacts its contents from custom dumps via the
CustomDumpStringConvertible
protocol:
struct Redacted<RawValue>: CustomDumpStringConvertible {
let rawValue: RawValue
var customDumpDescription: String {
"<redacted>"
}
}
struct LoginState: CustomDumpReflectable {
...
var customDumpMirror: Mirror {
.init(
self,
children: [
"email": self.email,
// redact password!
"password": Redacted(rawValue: self.password)
// omit token from logs
],
displayStyle: .struct
)
}
}
customDump(
LoginState(
email: "blob@pointfree.co",
password: "bl0bisawesome!",
token: "secret"
)
)
LoginState(
email: "blob@pointfree.co",
password: <redacted>
)
Now the dump retains the fact that a password field exists, but it prevents the underlying value from being logged.
Overriding a structure's dump representation
Massaging the data inside a structure is just one way to use a custom mirror. A mirror can also let you completely transform the way a structure is dumped.
For example, a wrapper type can be flattened to dump the wrapped value by providing the wrapped value's mirror:
struct Todos: CustomDumpReflectable {
var rawValue: [Todo] = []
var customDumpMirror: Mirror {
.init(reflecting: self.rawValue)
}
}
customDump(Todos())
[]
Requirements
customDumpMirror
var customDumpMirror: Mirror
The custom dump mirror for this instance.