public init<Subject>(describing instance: Subject) {
self.init()
_print_unlocked(instance, &self)
}
@inline(never)
@_semantics("stdlib_binary_only")
internal func _print_unlocked<T, TargetStream : TextOutputStream>(
_ value: T, _ target: inout TargetStream
) {
// Optional has no representation suitable for display; therefore,
// values of optional type should be printed as a debug
// string. Check for Optional first, before checking protocol
// conformance below, because an Optional value is convertible to a
// protocol if its wrapped type conforms to that protocol.
if _isOptional(type(of: value)) {
let debugPrintable = value as! CustomDebugStringConvertible
debugPrintable.debugDescription.write(to: &target)
return
}
if case let streamableObject as TextOutputStreamable = value {
streamableObject.write(to: &target)
return
}
if case let printableObject as CustomStringConvertible = value {
printableObject.description.write(to: &target)
return
}
if case let debugPrintableObject as CustomDebugStringConvertible = value {
debugPrintableObject.debugDescription.write(to: &target)
return
}
let mirror = Mirror(reflecting: value)
_adHocPrint_unlocked(value, mirror, &target, isDebugPrint: false)
}
/// Do our best to print a value that cannot be printed directly.
internal func _adHocPrint_unlocked<T, TargetStream : TextOutputStream>(
_ value: T, _ mirror: Mirror, _ target: inout TargetStream,
isDebugPrint: Bool
) {
func printTypeName(_ type: Any.Type) {
// Print type names without qualification, unless we're debugPrint'ing.
target.write(_typeName(type, qualified: isDebugPrint))
}
if let displayStyle = mirror.displayStyle {
switch displayStyle {
case .optional:
if let child = mirror.children.first {
_debugPrint_unlocked(child.1, &target)
} else {
_debugPrint_unlocked("nil", &target)
}
case .tuple:
target.write("(")
var first = true
for (label, value) in mirror.children {
if first {
first = false
} else {
target.write(", ")
}
if let label = label {
if !label.isEmpty && label[label.startIndex] != "." {
target.write(label)
target.write(": ")
}
}
_debugPrint_unlocked(value, &target)
}
target.write(")")
case .struct:
printTypeName(mirror.subjectType)
target.write("(")
var first = true
for (label, value) in mirror.children {
if let label = label {
if first {
first = false
} else {
target.write(", ")
}
target.write(label)
target.write(": ")
_debugPrint_unlocked(value, &target)
}
}
target.write(")")
case .enum:
if let cString = _getEnumCaseName(value),
let caseName = String(validatingUTF8: cString) {
// Write the qualified type name in debugPrint.
if isDebugPrint {
printTypeName(mirror.subjectType)
target.write(".")
}
target.write(caseName)
} else {
// If the case name is garbage, just print the type name.
printTypeName(mirror.subjectType)
}
if let (_, value) = mirror.children.first {
if Mirror(reflecting: value).displayStyle == .tuple {
_debugPrint_unlocked(value, &target)
} else {
target.write("(")
_debugPrint_unlocked(value, &target)
target.write(")")
}
}
default:
target.write(_typeName(mirror.subjectType))
}
} else if let metatypeValue = value as? Any.Type {
// Metatype
printTypeName(metatypeValue)
} else {
// Fall back to the type or an opaque summary of the kind
if let cString = _opaqueSummary(mirror.subjectType),
let opaqueSummary = String(validatingUTF8: cString) {
target.write(opaqueSummary)
} else {
target.write(_typeName(mirror.subjectType, qualified: true))
}
}
}
@_silgen_name("swift_EnumCaseName")
func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *type) {
// Build a magic mirror. Unconditionally destroy the value at the end.
const Metadata *mirrorType;
const OpaqueValue *cMirrorValue;
std::tie(mirrorType, cMirrorValue) = unwrapExistential(type, value);
OpaqueValue *mirrorValue = const_cast<OpaqueValue*>(cMirrorValue);
Mirror mirror;
bool take = mirrorValue == value;
::new (&mirror) MagicMirror(mirrorValue, mirrorType, take);
MagicMirror *theMirror = reinterpret_cast<MagicMirror *>(&mirror);
MagicMirrorData data = theMirror->Data;
const char *result = swift_EnumMirror_caseName(data.Owner, data.Value, data.Type);
return result;
}
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE
const char *swift_EnumMirror_caseName(HeapObject *owner,
const OpaqueValue *value,
const Metadata *type) {
if (!isEnumReflectable(type)) {
swift_release(owner);
return nullptr;
}
const auto Enum = static_cast<const EnumMetadata *>(type);
const auto &Description = Enum->Description->Enum;
unsigned tag;
getEnumMirrorInfo(value, type, &tag, nullptr, nullptr);
swift_release(owner);
return getFieldName(Description.CaseNames, tag);
}