From 1dc1e34b8b729c046c499e9122974876a4b36fa5 Mon Sep 17 00:00:00 2001 From: Iurii Khvorost Date: Thu, 14 Mar 2024 17:06:09 +0200 Subject: [PATCH] Code format --- Package.swift | 44 +- Sources/KeyValueCoding/Accessor.swift | 38 +- Sources/KeyValueCoding/Existential.swift | 12 +- Sources/KeyValueCoding/KeyValueCoding.swift | 188 ++--- Sources/KeyValueCoding/Metadata.swift | 274 ++++---- Sources/KeyValueCoding/ReflectionMirror.swift | 14 +- .../KeyValueCodingTests.swift | 647 +++++++++--------- 7 files changed, 608 insertions(+), 609 deletions(-) diff --git a/Package.swift b/Package.swift index 1fa3bc8..4bdb68c 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.3 +// swift-tools-version:5.7 // The swift-tools-version declares the minimum version of Swift required to build this package. // // Package.swift @@ -28,25 +28,25 @@ import PackageDescription let package = Package( - name: "KeyValueCoding", - platforms: [ - .iOS(.v12), - .macOS(.v10_14), - .tvOS(.v12), - .watchOS(.v5) - ], - products: [ - .library( - name: "KeyValueCoding", - targets: ["KeyValueCoding"]), - ], - targets: [ - .target( - name: "KeyValueCoding", - dependencies: []), - .testTarget( - name: "KeyValueCodingTests", - dependencies: ["KeyValueCoding"]), - ], - swiftLanguageVersions: [.v5] + name: "KeyValueCoding", + platforms: [ + .iOS(.v12), + .macOS(.v10_14), + .tvOS(.v12), + .watchOS(.v5) + ], + products: [ + .library( + name: "KeyValueCoding", + targets: ["KeyValueCoding"]), + ], + targets: [ + .target( + name: "KeyValueCoding", + dependencies: []), + .testTarget( + name: "KeyValueCodingTests", + dependencies: ["KeyValueCoding"]), + ], + swiftLanguageVersions: [.v5] ) diff --git a/Sources/KeyValueCoding/Accessor.swift b/Sources/KeyValueCoding/Accessor.swift index 89b7bcb..241998c 100644 --- a/Sources/KeyValueCoding/Accessor.swift +++ b/Sources/KeyValueCoding/Accessor.swift @@ -27,27 +27,27 @@ protocol Accessor {} extension Accessor { - - static func get(from pointer: UnsafeRawPointer) -> Any { - return pointer.assumingMemoryBound(to: Self.self).pointee - } - - static func set(value: Any, pointer: UnsafeMutableRawPointer) { - if let value = value as? Self { - pointer.assumingMemoryBound(to: self).pointee = value - } - } - - static var size: Int { - MemoryLayout.size + + static func get(from pointer: UnsafeRawPointer) -> Any { + return pointer.assumingMemoryBound(to: Self.self).pointee + } + + static func set(value: Any, pointer: UnsafeMutableRawPointer) { + if let value = value as? Self { + pointer.assumingMemoryBound(to: self).pointee = value } + } + + static var size: Int { + MemoryLayout.size + } } struct ProtocolTypeContainer { - let type: Any.Type - let witnessTable = 0 - - var accessor: Accessor.Type { - unsafeBitCast(self, to: Accessor.Type.self) - } + let type: Any.Type + let witnessTable = 0 + + var accessor: Accessor.Type { + unsafeBitCast(self, to: Accessor.Type.self) + } } diff --git a/Sources/KeyValueCoding/Existential.swift b/Sources/KeyValueCoding/Existential.swift index db40855..b9d8d41 100644 --- a/Sources/KeyValueCoding/Existential.swift +++ b/Sources/KeyValueCoding/Existential.swift @@ -28,13 +28,13 @@ import Foundation let ExistentialHeaderSize = 16 // 64bit struct ExistentialContainer { - let buffer: ExistentialContainerBuffer - let type: Any.Type - let witnessTable: Int + let buffer: ExistentialContainerBuffer + let type: Any.Type + let witnessTable: Int } struct ExistentialContainerBuffer { - let buffer1: Int - let buffer2: Int - let buffer3: Int + let buffer1: Int + let buffer2: Int + let buffer3: Int } diff --git a/Sources/KeyValueCoding/KeyValueCoding.swift b/Sources/KeyValueCoding/KeyValueCoding.swift index 2c36cf3..9999bb8 100644 --- a/Sources/KeyValueCoding/KeyValueCoding.swift +++ b/Sources/KeyValueCoding/KeyValueCoding.swift @@ -24,66 +24,66 @@ // fileprivate func withPointer(_ instance: inout T, _ body: (UnsafeMutableRawPointer, Metadata) -> Any?) -> Any? { - withUnsafePointer(to: &instance) { - let metadata = swift_metadata(of: T.self) - if metadata.kind == .struct { - return body(UnsafeMutableRawPointer(mutating: $0), metadata) + withUnsafePointer(to: &instance) { + let metadata = swift_metadata(of: T.self) + if metadata.kind == .struct { + return body(UnsafeMutableRawPointer(mutating: $0), metadata) + } + else if metadata.kind == .class { + return $0.withMemoryRebound(to: UnsafeMutableRawPointer.self, capacity: 1) { + body($0.pointee, metadata) + } + } + else if metadata.kind == .existential { + return $0.withMemoryRebound(to: ExistentialContainer.self, capacity: 1) { + let type = $0.pointee.type + let metadata = swift_metadata(of: type) + if metadata.kind == .class { + return $0.withMemoryRebound(to: UnsafeMutableRawPointer.self, capacity: 1) { + body($0.pointee, metadata) + } } - else if metadata.kind == .class { + else if metadata.kind == .struct { + if metadata.size > MemoryLayout.size { return $0.withMemoryRebound(to: UnsafeMutableRawPointer.self, capacity: 1) { - body($0.pointee, metadata) - } - } - else if metadata.kind == .existential { - return $0.withMemoryRebound(to: ExistentialContainer.self, capacity: 1) { - let type = $0.pointee.type - let metadata = swift_metadata(of: type) - if metadata.kind == .class { - return $0.withMemoryRebound(to: UnsafeMutableRawPointer.self, capacity: 1) { - body($0.pointee, metadata) - } - } - else if metadata.kind == .struct { - if metadata.size > MemoryLayout.size { - return $0.withMemoryRebound(to: UnsafeMutableRawPointer.self, capacity: 1) { - body($0.pointee.advanced(by: ExistentialHeaderSize), metadata) - } - } - else { - return body(UnsafeMutableRawPointer(mutating: $0), metadata) - } - } - return nil + body($0.pointee.advanced(by: ExistentialHeaderSize), metadata) } + } + else { + return body(UnsafeMutableRawPointer(mutating: $0), metadata) + } } return nil + } } + return nil + } } @discardableResult fileprivate func withProperty(_ instance: inout T, keyPath: [String], _ body: (Metadata, UnsafeMutableRawPointer) -> Any?) -> Any? { - withPointer(&instance) { pointer, metadata in - var keys = keyPath - guard let key = keys.popLast(), let property = (metadata.properties.first { $0.name == key }) else { - return nil - } - - let pointer = pointer.advanced(by: property.offset) - - if keys.isEmpty { - return body(property.metadata, pointer) - } - else if var value = property.metadata.get(from: pointer) { - defer { - let metadata = swift_metadata(of: type(of: value)) - if metadata.kind == .struct { - property.metadata.set(value: value, pointer: pointer) - } - } - return withProperty(&value, keyPath: keys, body) + withPointer(&instance) { pointer, metadata in + var keys = keyPath + guard let key = keys.popLast(), let property = (metadata.properties.first { $0.name == key }) else { + return nil + } + + let pointer = pointer.advanced(by: property.offset) + + if keys.isEmpty { + return body(property.metadata, pointer) + } + else if var value = property.metadata.get(from: pointer) { + defer { + let metadata = swift_metadata(of: type(of: value)) + if metadata.kind == .struct { + property.metadata.set(value: value, pointer: pointer) } - return nil + } + return withProperty(&value, keyPath: keys, body) } + return nil + } } // MARK: - @@ -94,7 +94,7 @@ fileprivate func withProperty(_ instance: inout T, keyPath: [String], _ body: /// - type: Type of a metatype instance. /// - Returns: Metadata of the type. public func swift_metadata(of type: Any.Type) -> Metadata { - MetadataCache.shared.metadata(of: type) + MetadataCache.shared.metadata(of: type) } /// Returns the metadata of the instance. @@ -103,8 +103,8 @@ public func swift_metadata(of type: Any.Type) -> Metadata { /// - instance: Instance of any type. /// - Returns: Metadata of the type. public func swift_metadata(of instance: Any) -> Metadata { - let type = type(of: instance) - return swift_metadata(of: type) + let type = type(of: instance) + return swift_metadata(of: type) } /// Returns the value for the instance's property identified by a given name or a key path. @@ -116,10 +116,10 @@ public func swift_metadata(of instance: Any) -> Metadata { /// for example “department.name” or “department.manager.lastName.” /// - Returns: The value for the property identified by a name or a key path. public func swift_value(of instance: inout T, key: String) -> Any? { - let keyPath: [String] = key.components(separatedBy: ".").reversed() - return withProperty(&instance, keyPath: keyPath) { metadata, pointer in - metadata.get(from: pointer) - } + let keyPath: [String] = key.components(separatedBy: ".").reversed() + return withProperty(&instance, keyPath: keyPath) { metadata, pointer in + metadata.get(from: pointer) + } } /// Sets a property of an instance specified by a given name or a key path to a given value. @@ -131,10 +131,10 @@ public func swift_value(of instance: inout T, key: String) -> Any? { /// relationship.property (with one or more relationships): /// for example “department.name” or “department.manager.lastName.” public func swift_setValue(_ value: Any?, to: inout T, key: String) { - let keyPath: [String] = key.components(separatedBy: ".").reversed() - withProperty(&to, keyPath: keyPath) { metadata, pointer in - metadata.set(value: value as Any, pointer: pointer) - } + let keyPath: [String] = key.components(separatedBy: ".").reversed() + withProperty(&to, keyPath: keyPath) { metadata, pointer in + metadata.set(value: value as Any, pointer: pointer) + } } // MARK: - KeyValueCoding @@ -143,41 +143,41 @@ public func swift_setValue(_ value: Any?, to: inout T, key: String) { public protocol KeyValueCoding {} extension KeyValueCoding { - - /// Returns the metadata of the instance type. - public var metadata: Metadata { - swift_metadata(of: self) + + /// Returns the metadata of the instance type. + public var metadata: Metadata { + swift_metadata(of: self) + } + + /// Returns a value for a property identified by a given name or a key path. + /// + /// - Parameters: + /// - key: The name of one of the instance's properties or a key path of the form + /// relationship.property (with one or more relationships): + /// for example “department.name” or “department.manager.lastName.” + /// - Returns: The value for the property identified by a name or a key path. + public mutating func value(key: String) -> Any? { + swift_value(of: &self, key: key) + } + + /// Sets a property specified by a given name or a key path to a given value. + /// + /// - Parameters: + /// - value: The value for the property identified by a name or a key path. + /// - key: The name of one of the instance's properties or a key path of the form + /// relationship.property (with one or more relationships): + /// for example “department.name” or “department.manager.lastName.” + public mutating func setValue(_ value: Any?, key: String) { + swift_setValue(value, to: &self, key: key) + } + + /// Gets and sets a value for a property identified by a given name or a key path. + public subscript(key: String) -> Any? { + mutating get { + value(key: key) } - - /// Returns a value for a property identified by a given name or a key path. - /// - /// - Parameters: - /// - key: The name of one of the instance's properties or a key path of the form - /// relationship.property (with one or more relationships): - /// for example “department.name” or “department.manager.lastName.” - /// - Returns: The value for the property identified by a name or a key path. - public mutating func value(key: String) -> Any? { - swift_value(of: &self, key: key) - } - - /// Sets a property specified by a given name or a key path to a given value. - /// - /// - Parameters: - /// - value: The value for the property identified by a name or a key path. - /// - key: The name of one of the instance's properties or a key path of the form - /// relationship.property (with one or more relationships): - /// for example “department.name” or “department.manager.lastName.” - public mutating func setValue(_ value: Any?, key: String) { - swift_setValue(value, to: &self, key: key) - } - - /// Gets and sets a value for a property identified by a given name or a key path. - public subscript(key: String) -> Any? { - mutating get { - value(key: key) - } - set { - setValue(newValue, key: key) - } + set { + setValue(newValue, key: key) } + } } diff --git a/Sources/KeyValueCoding/Metadata.swift b/Sources/KeyValueCoding/Metadata.swift index 67f4326..799e792 100644 --- a/Sources/KeyValueCoding/Metadata.swift +++ b/Sources/KeyValueCoding/Metadata.swift @@ -29,169 +29,169 @@ import Foundation @discardableResult fileprivate func synchronized(_ obj: T, closure: () -> U) -> U { - objc_sync_enter(obj) - defer { - objc_sync_exit(obj) - } - return closure() + objc_sync_enter(obj) + defer { + objc_sync_exit(obj) + } + return closure() } /// Metadata for a type. public struct Metadata { + + /// The metadata kind for a type. + public enum Kind: UInt { + // With "flags": + // runtimePrivate = 0x100 + // nonHeap = 0x200 + // nonType = 0x400 - /// The metadata kind for a type. - public enum Kind: UInt { - // With "flags": - // runtimePrivate = 0x100 - // nonHeap = 0x200 - // nonType = 0x400 - - /// Class metadata kind. - case `class` = 0 - /// Struct metadata kind. - case `struct` = 0x200 // 0 | nonHeap - /// Enum metadata kind. - case `enum` = 0x201 // 1 | nonHeap - /// Optional metadata kind. - case optional = 0x202 // 2 | nonHeap - /// Foreign class metadata kind. - case foreignClass = 0x203 // 3 | nonHeap - /// Opaque metadata kind. - case opaque = 0x300 // 0 | runtimePrivate | nonHeap - /// Tuple metadata kind. - case tuple = 0x301 // 1 | runtimePrivate | nonHeap - /// Function metadata kind. - case function = 0x302 // 2 | runtimePrivate | nonHeap - /// Existential metadata kind. - case existential = 0x303 // 3 | runtimePrivate | nonHeap - /// Metatype metadata kind. - case metatype = 0x304 // 4 | runtimePrivate | nonHeap - /// Objc class wrapper metadata kind. - case objcClassWrapper = 0x305 // 5 | runtimePrivate | nonHeap - /// Existential metatype metadata kind. - case existentialMetatype = 0x306 // 6 | runtimePrivate | nonHeap - /// Heap local variable metadata kind. - case heapLocalVariable = 0x400 // 0 | nonType - /// Heap generic local variable metadata kind. - case heapGenericLocalVariable = 0x500 // 0 | nonType | runtimePrivate - /// Error object metadata kind. - case errorObject = 0x501 // 1 | nonType | runtimePrivate - /// Unknown metadata kind. - case unknown = 0xffff - - static func kind(of type: Any.Type) -> Self { - let kind = swift_getMetadataKind(type) - return Self(rawValue: kind) ?? .unknown - } - } + /// Class metadata kind. + case `class` = 0 + /// Struct metadata kind. + case `struct` = 0x200 // 0 | nonHeap + /// Enum metadata kind. + case `enum` = 0x201 // 1 | nonHeap + /// Optional metadata kind. + case optional = 0x202 // 2 | nonHeap + /// Foreign class metadata kind. + case foreignClass = 0x203 // 3 | nonHeap + /// Opaque metadata kind. + case opaque = 0x300 // 0 | runtimePrivate | nonHeap + /// Tuple metadata kind. + case tuple = 0x301 // 1 | runtimePrivate | nonHeap + /// Function metadata kind. + case function = 0x302 // 2 | runtimePrivate | nonHeap + /// Existential metadata kind. + case existential = 0x303 // 3 | runtimePrivate | nonHeap + /// Metatype metadata kind. + case metatype = 0x304 // 4 | runtimePrivate | nonHeap + /// Objc class wrapper metadata kind. + case objcClassWrapper = 0x305 // 5 | runtimePrivate | nonHeap + /// Existential metatype metadata kind. + case existentialMetatype = 0x306 // 6 | runtimePrivate | nonHeap + /// Heap local variable metadata kind. + case heapLocalVariable = 0x400 // 0 | nonType + /// Heap generic local variable metadata kind. + case heapGenericLocalVariable = 0x500 // 0 | nonType | runtimePrivate + /// Error object metadata kind. + case errorObject = 0x501 // 1 | nonType | runtimePrivate + /// Unknown metadata kind. + case unknown = 0xffff - /// Property details. - public struct Property { - /// Name of the property. - public let name: String - - /// Is strong referenced property. - public let isStrong: Bool - - /// Is variable property. - public let isVar: Bool - - /// Offset of the property. - public let offset: Int - - /// Metadata of the property. - public let metadata: Metadata + static func kind(of type: Any.Type) -> Self { + let kind = swift_getMetadataKind(type) + return Self(rawValue: kind) ?? .unknown } + } + + /// Property details. + public struct Property { + /// Name of the property. + public let name: String - private let container: ProtocolTypeContainer - - /// Type. - public let type: Any.Type + /// Is strong referenced property. + public let isStrong: Bool - /// Kind of the type. - public let kind: Kind + /// Is variable property. + public let isVar: Bool - /// Size of the type. - public var size: Int { container.accessor.size } + /// Offset of the property. + public let offset: Int - /// Accessible properties of the type. - public let properties: [Property] - - private static func enumProperties(type: Any.Type, kind: Kind) -> [Property] { - guard kind == .class || kind == .struct else { - return [] - } - - let count = swift_reflectionMirror_recursiveCount(type) - var fieldMetadata = _FieldReflectionMetadata() - return (0.. [Property] { + guard kind == .class || kind == .struct else { + return [] } - fileprivate init(type: Any.Type) { - self.type = type - self.kind = Kind.kind(of: type) - self.container = ProtocolTypeContainer(type: type) - self.properties = Self.enumProperties(type: type, kind: self.kind) + let count = swift_reflectionMirror_recursiveCount(type) + var fieldMetadata = _FieldReflectionMetadata() + return (0.. Any? { + let value = container.accessor.get(from: pointer) - func get(from pointer: UnsafeRawPointer) -> Any? { - let value = container.accessor.get(from: pointer) - - // Optional - if kind == .optional { - let mirror = Mirror(reflecting: value) - return mirror.children.first?.value - } - - return value + // Optional + if kind == .optional { + let mirror = Mirror(reflecting: value) + return mirror.children.first?.value } - func set(value: Any, pointer: UnsafeMutableRawPointer) { - container.accessor.set(value: value as Any, pointer: pointer) - } + return value + } + + func set(value: Any, pointer: UnsafeMutableRawPointer) { + container.accessor.set(value: value as Any, pointer: pointer) + } } extension Metadata.Property: CustomStringConvertible { - /// A textual representation the `Metadata.Property`. - public var description: String { - return "Property(name: '\(name)', isStrong: \(isStrong), isVar: \(isVar), offset: \(offset))" - } + /// A textual representation the `Metadata.Property`. + public var description: String { + return "Property(name: '\(name)', isStrong: \(isStrong), isVar: \(isVar), offset: \(offset))" + } } extension Metadata: CustomStringConvertible { - /// A textual representation the `Metadata`. - public var description: String { - return "Metadata(type: \(type), kind: .\(kind), size: \(size), properties: \(properties))" - } + /// A textual representation the `Metadata`. + public var description: String { + return "Metadata(type: \(type), kind: .\(kind), size: \(size), properties: \(properties))" + } } class MetadataCache { - - static let shared = MetadataCache() - - private var cache = [String : Metadata]() - - func metadata(of type: Any.Type) -> Metadata { - synchronized(self) { - let key = String(describing: type) - guard let metadata = cache[key] else { - let metadata = Metadata(type: type) - cache[key] = metadata - return metadata - } - return metadata - } + + static let shared = MetadataCache() + + private var cache = [String : Metadata]() + + func metadata(of type: Any.Type) -> Metadata { + synchronized(self) { + let key = String(describing: type) + guard let metadata = cache[key] else { + let metadata = Metadata(type: type) + cache[key] = metadata + return metadata + } + return metadata } + } } diff --git a/Sources/KeyValueCoding/ReflectionMirror.swift b/Sources/KeyValueCoding/ReflectionMirror.swift index de4ebcb..fb6ad2b 100644 --- a/Sources/KeyValueCoding/ReflectionMirror.swift +++ b/Sources/KeyValueCoding/ReflectionMirror.swift @@ -27,10 +27,10 @@ typealias NameFreeFunc = @convention(c) (UnsafePointer?) -> Void struct _FieldReflectionMetadata { - let name: UnsafePointer? = nil - let freeFunc: NameFreeFunc? = nil - let isStrong: Bool = false - let isVar: Bool = false + let name: UnsafePointer? = nil + let freeFunc: NameFreeFunc? = nil + let isStrong: Bool = false + let isVar: Bool = false } @_silgen_name("swift_reflectionMirror_recursiveCount") @@ -38,9 +38,9 @@ func swift_reflectionMirror_recursiveCount(_: Any.Type) -> Int @_silgen_name("swift_reflectionMirror_recursiveChildMetadata") func swift_reflectionMirror_recursiveChildMetadata( - _: Any.Type - , index: Int - , fieldMetadata: UnsafeMutablePointer<_FieldReflectionMetadata> + _: Any.Type + , index: Int + , fieldMetadata: UnsafeMutablePointer<_FieldReflectionMetadata> ) -> Any.Type @_silgen_name("swift_reflectionMirror_recursiveChildOffset") diff --git a/Tests/KeyValueCodingTests/KeyValueCodingTests.swift b/Tests/KeyValueCodingTests/KeyValueCodingTests.swift index ac03aeb..5884859 100644 --- a/Tests/KeyValueCodingTests/KeyValueCodingTests.swift +++ b/Tests/KeyValueCodingTests/KeyValueCodingTests.swift @@ -1,366 +1,365 @@ import XCTest -import KeyValueCoding -//@testable import KeyValueCoding +/*@testable*/ import KeyValueCoding enum UserType { - case none - case guest - case user - case admin + case none + case guest + case user + case admin } class ClassInfo: Equatable { - let phone: String - let email: String - - init(phone: String, email: String) { - self.phone = phone - self.email = email - } - - static func == (lhs: ClassInfo, rhs: ClassInfo) -> Bool { - lhs.phone == rhs.phone && lhs.email == rhs.email - } + let phone: String + let email: String + + init(phone: String, email: String) { + self.phone = phone + self.email = email + } + + static func == (lhs: ClassInfo, rhs: ClassInfo) -> Bool { + lhs.phone == rhs.phone && lhs.email == rhs.email + } } struct StructInfo: Equatable { - let phone: String - let email: String + let phone: String + let email: String } protocol UserProtocol: KeyValueCoding { - var id: Int { get } - var name: String? { get } - var type: UserType { get } - var array: [Int] { get } - var classInfo: ClassInfo { get } - var classInfoOptional: ClassInfo? { get } - var structInfo: StructInfo { get } - var structInfoOptional: StructInfo? { get } - var observed: Int { get set } - var computed: Int { get } + var id: Int { get } + var name: String? { get } + var type: UserType { get } + var array: [Int] { get } + var classInfo: ClassInfo { get } + var classInfoOptional: ClassInfo? { get } + var structInfo: StructInfo { get } + var structInfoOptional: StructInfo? { get } + var observed: Int { get set } + var computed: Int { get } } class UserClass: UserProtocol { - let id = 0 - let name: String? = nil - var type: UserType = .none - let array: [Int] = [Int]() - let classInfo = ClassInfo(phone: "", email: "") - var classInfoOptional: ClassInfo? = nil - let structInfo = StructInfo(phone: "", email: "") - var structInfoOptional: StructInfo? = nil - var observed: Int = 0 { - willSet { XCTFail() } - didSet { XCTFail() } - } - var computed: Int { - XCTFail(); - return 0 - } + let id = 0 + let name: String? = nil + var type: UserType = .none + let array: [Int] = [Int]() + let classInfo = ClassInfo(phone: "", email: "") + var classInfoOptional: ClassInfo? = nil + let structInfo = StructInfo(phone: "", email: "") + var structInfoOptional: StructInfo? = nil + var observed: Int = 0 { + willSet { XCTFail() } + didSet { XCTFail() } + } + var computed: Int { + XCTFail(); + return 0 + } } class UserClass2: UserClass { - private let promoCode: Int = 0 + private let promoCode: Int = 0 } class UserClassObjC: NSObject, UserProtocol { - @objc let id = 0 - @objc let name: String? = nil - var type: UserType = .none - @objc let array: [Int] = [Int]() - let classInfo = ClassInfo(phone: "", email: "") - let classInfoOptional: ClassInfo? = nil - let structInfo = StructInfo(phone: "", email: "") - var structInfoOptional: StructInfo? = nil - var observed: Int = 0 { - willSet { XCTFail() } - didSet { XCTFail() } - } - var computed: Int { - XCTFail(); - return 0 - } + @objc let id = 0 + @objc let name: String? = nil + var type: UserType = .none + @objc let array: [Int] = [Int]() + let classInfo = ClassInfo(phone: "", email: "") + let classInfoOptional: ClassInfo? = nil + let structInfo = StructInfo(phone: "", email: "") + var structInfoOptional: StructInfo? = nil + var observed: Int = 0 { + willSet { XCTFail() } + didSet { XCTFail() } + } + var computed: Int { + XCTFail(); + return 0 + } } struct UserStruct: UserProtocol { - let id = 0 - let name: String? = nil - var type: UserType = .none - let array: [Int] = [Int]() - let classInfo = ClassInfo(phone: "", email: "") - let classInfoOptional: ClassInfo? = nil - let structInfo = StructInfo(phone: "", email: "") - var structInfoOptional: StructInfo? = nil - var observed: Int = 0 { - willSet { XCTFail() } - didSet { XCTFail() } - } - var computed: Int { - XCTFail(); - return 0 - } + let id = 0 + let name: String? = nil + var type: UserType = .none + let array: [Int] = [Int]() + let classInfo = ClassInfo(phone: "", email: "") + let classInfoOptional: ClassInfo? = nil + let structInfo = StructInfo(phone: "", email: "") + var structInfoOptional: StructInfo? = nil + var observed: Int = 0 { + willSet { XCTFail() } + didSet { XCTFail() } + } + var computed: Int { + XCTFail(); + return 0 + } } protocol SongProtocol: KeyValueCoding { - var name: String { get set } + var name: String { get set } } struct Song: SongProtocol { - var name: String + var name: String } final class KeyValueCodingTests: XCTestCase { + + func test_keyValueCoding(_ user: inout T, kind: Metadata.Kind, propertiesCount: Int = 9) { - func test_keyValueCoding(_ user: inout T, kind: Metadata.Kind, propertiesCount: Int = 9) { - - // Metadata - - let metadata = swift_metadata(of: user) - XCTAssert(swift_metadata(of: T.self).kind == kind) - XCTAssert(metadata.kind == kind) - XCTAssert(user.metadata.kind == kind) - XCTAssert(metadata.description.hasPrefix("Metadata(type: \(String(describing: metadata.type)), kind: .\(kind), size: \(metadata.size)")) - - let properties = metadata.properties - XCTAssert(properties.count == propertiesCount) - - if kind == .class { - XCTAssert(metadata.size == 8) - } - else { - XCTAssert(metadata.size == 128) - } - - let property = user.metadata.properties[0] - XCTAssert(property.name == "id") - XCTAssert(property.metadata.type is Int.Type) - XCTAssert(property.metadata.type == Int.self) - XCTAssert(property.isStrong == true) - XCTAssert(property.isVar == false) - XCTAssert(property.description == "Property(name: \'id\', isStrong: true, isVar: false, offset: \(property.offset))") - - // Nil - XCTAssertNil(user[""]) - XCTAssertNil(user["."]) - XCTAssertNil(user["..."]) - XCTAssertNil(user["undefined"]) - XCTAssertNil(user["name"]) - XCTAssertNil(user["classInfo.undefined"]) - XCTAssertNil(user["classInfoOptional"]) - XCTAssertNil(user["classInfoOptional.undefined"]) - XCTAssertNil(user["classInfoOptional.email"]) - XCTAssertNil(user["structInfoOptional"]) - XCTAssertNil(user["structInfoOptional.undefined"]) - XCTAssertNil(user["structInfoOptional.email"]) - - // Set value - - let array = [1, 2, 3] - let classInfo = ClassInfo(phone: "1234567890", email: "mail@domain.com") - let structInfo = StructInfo(phone: "1234567890", email: "mail@domain.com") - - swift_setValue(1, to: &user, key: "id") - swift_setValue("Bob", to: &user, key: "name") - swift_setValue(UserType.admin, to: &user, key: "type") - swift_setValue(array, to: &user, key: "array") - swift_setValue(classInfo, to: &user, key: "classInfo") - swift_setValue(classInfo, to: &user, key: "classInfoOptional") - swift_setValue(structInfo, to: &user, key: "structInfo") - swift_setValue(structInfo, to: &user, key: "structInfoOptional") - XCTAssert(user.id == 1) - XCTAssert(user.name == "Bob") - XCTAssert(user.type == .admin) - XCTAssert(user.array == array) - XCTAssert(user.classInfo == classInfo) - XCTAssert(user.classInfoOptional == classInfo) - XCTAssert(user.structInfo == structInfo) - XCTAssert(user.structInfoOptional == structInfo) - - user.setValue(2, key: "id") - user.setValue(nil, key: "name") - user.setValue(UserType.guest, key: "type") - user.setValue([], key: "array") - user.setValue(ClassInfo(phone:"", email: ""), key: "classInfo") - user.setValue(ClassInfo(phone:"", email: ""), key: "classInfoOptional") - user.setValue(StructInfo(phone:"", email: ""), key: "structInfo") - user.setValue(StructInfo(phone:"", email: ""), key: "structInfoOptional") - XCTAssert(user.id == 2) - XCTAssert(user.name == nil) - XCTAssert(user.type == .guest) - XCTAssert(user.array == []) - XCTAssert(user.classInfo == ClassInfo(phone:"", email: "")) - XCTAssert(user.classInfoOptional == ClassInfo(phone:"", email: "")) - XCTAssert(user.structInfo == StructInfo(phone:"", email: "")) - XCTAssert(user.structInfoOptional == StructInfo(phone:"", email: "")) - - user[""] = "" - user["id"] = 3 - user["name"] = "Alice" - user["type"] = UserType.user - user["array"] = array - user["classInfo"] = classInfo - user["classInfoOptional"] = classInfo - user["structInfo"] = structInfo - user["structInfoOptional"] = structInfo - XCTAssert(user.id == 3) - XCTAssert(user.name == "Alice") - XCTAssert(user.type == .user) - XCTAssert(user.array == array) - XCTAssert(user.classInfo == classInfo) - XCTAssert(user.classInfoOptional == classInfo) - XCTAssert(user.structInfo == structInfo) - XCTAssert(user.structInfoOptional == structInfo) - - // Get value - - XCTAssertNil(swift_value(of: &user, key: "undefined")) - XCTAssert(swift_value(of: &user, key: "id") as? Int == 3) - XCTAssert(swift_value(of: &user, key: "name") as? String == "Alice") - XCTAssert(swift_value(of: &user, key: "type") as? UserType == .user) - XCTAssert(swift_value(of: &user, key: "array") as? [Int] == array) - XCTAssert(swift_value(of: &user, key: "classInfo") as? ClassInfo == classInfo) - XCTAssert(swift_value(of: &user, key: "classInfoOptional") as? ClassInfo == classInfo) - XCTAssert(swift_value(of: &user, key: "structInfo") as? StructInfo == structInfo) - XCTAssert(swift_value(of: &user, key: "structInfoOptional") as? StructInfo == structInfo) - - XCTAssertNil(user.value(key: "undefined")) - XCTAssert(user.value(key: "id") as? Int == 3) - XCTAssert(user.value(key: "name") as? String == "Alice") - XCTAssert(user.value(key: "type") as? UserType == .user) - XCTAssert(user.value(key: "array") as? [Int] == array) - XCTAssert(user.value(key: "classInfo") as? ClassInfo == classInfo) - XCTAssert(user.value(key: "classInfoOptional") as? ClassInfo == classInfo) - XCTAssert(user.value(key: "structInfo") as? StructInfo == structInfo) - XCTAssert(user.value(key: "structInfoOptional") as? StructInfo == structInfo) - - XCTAssertNil(user["undefined"]) - XCTAssert(user["id"] as? Int == 3) - XCTAssert(user["name"] as? String == "Alice") - XCTAssert(user["type"] as? UserType == .user) - XCTAssert(user["array"] as? [Int] == array) - XCTAssert(user["classInfo"] as? ClassInfo == classInfo) - XCTAssert(user["classInfoOptional"] as? ClassInfo == classInfo) - XCTAssert(user["structInfo"] as? StructInfo == structInfo) - XCTAssert(user["structInfoOptional"] as? StructInfo == structInfo) - - // Set wrong type - - user["id"] = "Hello" - user["name"] = 11 - user["type"] = nil - user["array"] = ["1", "2"] - user["classInfo"] = "123" - user["classInfo.phone"] = 10 - user["classInfoOptioanal"] = "123" - user["classInfoOptioanal.phone"] = 10 - user["structInfo"] = "123" - user["structInfo.phone"] = 10 - user["structInfoOptioanal"] = "123" - user["structInfoOptioanal.phone"] = 10 - XCTAssert(user["id"] as? Int == 3) - XCTAssert(user["name"] as? String == "Alice") - XCTAssert(user["type"] as? UserType == .user) - XCTAssert(user["array"] as? [Int] == array) - XCTAssert(user["classInfo"] as? ClassInfo == classInfo) - XCTAssert(user["classInfoOptional"] as? ClassInfo == classInfo) - XCTAssert(user["structInfo"] as? StructInfo == structInfo) - XCTAssert(user["structInfoOptional"] as? StructInfo == structInfo) - - - // Key path - - user["classInfo"] = classInfo - user["classInfoOptional"] = classInfo - user["structInfo"] = structInfo - user["structInfoOptional"] = structInfo - XCTAssert(user["classInfo.email"] as? String == classInfo.email) - XCTAssert(user["classInfoOptional.email"] as? String == classInfo.email) - XCTAssert(user["structInfo.email"] as? String == structInfo.email) - XCTAssert(user["structInfoOptional.email"] as? String == structInfo.email) - - let email = "my@my.com" - user["classInfo.email"] = email - user["classInfoOptional.email"] = email - user["structInfo.email"] = email - user["structInfoOptional.email"] = email - XCTAssert(user["classInfo.email"] as? String == email) - XCTAssert(user["classInfoOptional.email"] as? String == email) - XCTAssert(user["structInfo.email"] as? String == email) - XCTAssert(user["structInfoOptional.email"] as? String == email) - - user["classInfoOptional"] = nil - user["structInfoOptional"] = nil - XCTAssertNil(user["classInfoOptional"]) - XCTAssertNil(user["classInfoOptional.email"]) - XCTAssertNil(user["structInfoOptional"]) - XCTAssertNil(user["structInfoOptional.email"]) - - // Observed - user["observed"] = 10 - - // Computed - user["computed"] = 100 - XCTAssertNil(user["computed"]) - } + // Metadata - func test_class() { - var user = UserClass() - test_keyValueCoding(&user, kind: .class) - - // Existential - /* - var p: UserProtocol = user - swift_setValue(777, to: &p, key: "id") - XCTAssert(swift_value(of: &p, key: "id") as? Int == 777) - */ - } + let metadata = swift_metadata(of: user) + XCTAssert(swift_metadata(of: T.self).kind == kind) + XCTAssert(metadata.kind == kind) + XCTAssert(user.metadata.kind == kind) + XCTAssert(metadata.description.hasPrefix("Metadata(type: \(String(describing: metadata.type)), kind: .\(kind), size: \(metadata.size)")) - func test_class_inheritance() { - var user = UserClass2() - test_keyValueCoding(&user, kind: .class, propertiesCount: 10) - - user["id"] = 100 - user["name"] = "Jack" - XCTAssert(user["id"] as? Int == 100) - XCTAssert(user["name"] as? String == "Jack") - - // Private - user["promoCode"] = 100 - XCTAssert(user["promoCode"] as? Int == 100) - } + let properties = metadata.properties + XCTAssert(properties.count == propertiesCount) - func test_class_objc() { - var user = UserClassObjC() - test_keyValueCoding(&user, kind: .class) + if kind == .class { + XCTAssert(metadata.size == 8) } - - func test_struct() { - var user = UserStruct() - test_keyValueCoding(&user, kind: .struct) - - // Existential - /* - var p: UserProtocol = user - swift_setValue(777, to: &p, key: "id") - XCTAssert(swift_value(of: &p, key: "id") as? Int == 777) - */ - - var song: SongProtocol = Song(name: "") - swift_setValue("Blue Suede Shoes", to: &song, key: "name") - XCTAssert(swift_value(of: &song, key: "name") as? String == "Blue Suede Shoes") + else { + XCTAssert(metadata.size == 128) } - func test_optional() { - var optional: UserClass? = UserClass() - test_keyValueCoding(&optional!, kind: .class) - - optional?["id"] = 123 - XCTAssert(optional?["id"] as? Int == 123) - XCTAssert(optional?.value(key: "id") as? Int == 123) - XCTAssert(swift_value(of: &optional!, key: "id") as? Int == 123) - - XCTAssertNil(swift_value(of: &optional, key: "id")) - } + let property = user.metadata.properties[0] + XCTAssert(property.name == "id") + XCTAssert(property.metadata.type is Int.Type) + XCTAssert(property.metadata.type == Int.self) + XCTAssert(property.isStrong == true) + XCTAssert(property.isVar == false) + XCTAssert(property.description == "Property(name: \'id\', isStrong: true, isVar: false, offset: \(property.offset))") + + // Nil + XCTAssertNil(user[""]) + XCTAssertNil(user["."]) + XCTAssertNil(user["..."]) + XCTAssertNil(user["undefined"]) + XCTAssertNil(user["name"]) + XCTAssertNil(user["classInfo.undefined"]) + XCTAssertNil(user["classInfoOptional"]) + XCTAssertNil(user["classInfoOptional.undefined"]) + XCTAssertNil(user["classInfoOptional.email"]) + XCTAssertNil(user["structInfoOptional"]) + XCTAssertNil(user["structInfoOptional.undefined"]) + XCTAssertNil(user["structInfoOptional.email"]) + + // Set value + + let array = [1, 2, 3] + let classInfo = ClassInfo(phone: "1234567890", email: "mail@domain.com") + let structInfo = StructInfo(phone: "1234567890", email: "mail@domain.com") + + swift_setValue(1, to: &user, key: "id") + swift_setValue("Bob", to: &user, key: "name") + swift_setValue(UserType.admin, to: &user, key: "type") + swift_setValue(array, to: &user, key: "array") + swift_setValue(classInfo, to: &user, key: "classInfo") + swift_setValue(classInfo, to: &user, key: "classInfoOptional") + swift_setValue(structInfo, to: &user, key: "structInfo") + swift_setValue(structInfo, to: &user, key: "structInfoOptional") + XCTAssert(user.id == 1) + XCTAssert(user.name == "Bob") + XCTAssert(user.type == .admin) + XCTAssert(user.array == array) + XCTAssert(user.classInfo == classInfo) + XCTAssert(user.classInfoOptional == classInfo) + XCTAssert(user.structInfo == structInfo) + XCTAssert(user.structInfoOptional == structInfo) + + user.setValue(2, key: "id") + user.setValue(nil, key: "name") + user.setValue(UserType.guest, key: "type") + user.setValue([], key: "array") + user.setValue(ClassInfo(phone:"", email: ""), key: "classInfo") + user.setValue(ClassInfo(phone:"", email: ""), key: "classInfoOptional") + user.setValue(StructInfo(phone:"", email: ""), key: "structInfo") + user.setValue(StructInfo(phone:"", email: ""), key: "structInfoOptional") + XCTAssert(user.id == 2) + XCTAssert(user.name == nil) + XCTAssert(user.type == .guest) + XCTAssert(user.array == []) + XCTAssert(user.classInfo == ClassInfo(phone:"", email: "")) + XCTAssert(user.classInfoOptional == ClassInfo(phone:"", email: "")) + XCTAssert(user.structInfo == StructInfo(phone:"", email: "")) + XCTAssert(user.structInfoOptional == StructInfo(phone:"", email: "")) + + user[""] = "" + user["id"] = 3 + user["name"] = "Alice" + user["type"] = UserType.user + user["array"] = array + user["classInfo"] = classInfo + user["classInfoOptional"] = classInfo + user["structInfo"] = structInfo + user["structInfoOptional"] = structInfo + XCTAssert(user.id == 3) + XCTAssert(user.name == "Alice") + XCTAssert(user.type == .user) + XCTAssert(user.array == array) + XCTAssert(user.classInfo == classInfo) + XCTAssert(user.classInfoOptional == classInfo) + XCTAssert(user.structInfo == structInfo) + XCTAssert(user.structInfoOptional == structInfo) + + // Get value + + XCTAssertNil(swift_value(of: &user, key: "undefined")) + XCTAssert(swift_value(of: &user, key: "id") as? Int == 3) + XCTAssert(swift_value(of: &user, key: "name") as? String == "Alice") + XCTAssert(swift_value(of: &user, key: "type") as? UserType == .user) + XCTAssert(swift_value(of: &user, key: "array") as? [Int] == array) + XCTAssert(swift_value(of: &user, key: "classInfo") as? ClassInfo == classInfo) + XCTAssert(swift_value(of: &user, key: "classInfoOptional") as? ClassInfo == classInfo) + XCTAssert(swift_value(of: &user, key: "structInfo") as? StructInfo == structInfo) + XCTAssert(swift_value(of: &user, key: "structInfoOptional") as? StructInfo == structInfo) + + XCTAssertNil(user.value(key: "undefined")) + XCTAssert(user.value(key: "id") as? Int == 3) + XCTAssert(user.value(key: "name") as? String == "Alice") + XCTAssert(user.value(key: "type") as? UserType == .user) + XCTAssert(user.value(key: "array") as? [Int] == array) + XCTAssert(user.value(key: "classInfo") as? ClassInfo == classInfo) + XCTAssert(user.value(key: "classInfoOptional") as? ClassInfo == classInfo) + XCTAssert(user.value(key: "structInfo") as? StructInfo == structInfo) + XCTAssert(user.value(key: "structInfoOptional") as? StructInfo == structInfo) + + XCTAssertNil(user["undefined"]) + XCTAssert(user["id"] as? Int == 3) + XCTAssert(user["name"] as? String == "Alice") + XCTAssert(user["type"] as? UserType == .user) + XCTAssert(user["array"] as? [Int] == array) + XCTAssert(user["classInfo"] as? ClassInfo == classInfo) + XCTAssert(user["classInfoOptional"] as? ClassInfo == classInfo) + XCTAssert(user["structInfo"] as? StructInfo == structInfo) + XCTAssert(user["structInfoOptional"] as? StructInfo == structInfo) + + // Set wrong type + + user["id"] = "Hello" + user["name"] = 11 + user["type"] = nil + user["array"] = ["1", "2"] + user["classInfo"] = "123" + user["classInfo.phone"] = 10 + user["classInfoOptioanal"] = "123" + user["classInfoOptioanal.phone"] = 10 + user["structInfo"] = "123" + user["structInfo.phone"] = 10 + user["structInfoOptioanal"] = "123" + user["structInfoOptioanal.phone"] = 10 + XCTAssert(user["id"] as? Int == 3) + XCTAssert(user["name"] as? String == "Alice") + XCTAssert(user["type"] as? UserType == .user) + XCTAssert(user["array"] as? [Int] == array) + XCTAssert(user["classInfo"] as? ClassInfo == classInfo) + XCTAssert(user["classInfoOptional"] as? ClassInfo == classInfo) + XCTAssert(user["structInfo"] as? StructInfo == structInfo) + XCTAssert(user["structInfoOptional"] as? StructInfo == structInfo) + + + // Key path + + user["classInfo"] = classInfo + user["classInfoOptional"] = classInfo + user["structInfo"] = structInfo + user["structInfoOptional"] = structInfo + XCTAssert(user["classInfo.email"] as? String == classInfo.email) + XCTAssert(user["classInfoOptional.email"] as? String == classInfo.email) + XCTAssert(user["structInfo.email"] as? String == structInfo.email) + XCTAssert(user["structInfoOptional.email"] as? String == structInfo.email) + + let email = "my@my.com" + user["classInfo.email"] = email + user["classInfoOptional.email"] = email + user["structInfo.email"] = email + user["structInfoOptional.email"] = email + XCTAssert(user["classInfo.email"] as? String == email) + XCTAssert(user["classInfoOptional.email"] as? String == email) + XCTAssert(user["structInfo.email"] as? String == email) + XCTAssert(user["structInfoOptional.email"] as? String == email) + + user["classInfoOptional"] = nil + user["structInfoOptional"] = nil + XCTAssertNil(user["classInfoOptional"]) + XCTAssertNil(user["classInfoOptional.email"]) + XCTAssertNil(user["structInfoOptional"]) + XCTAssertNil(user["structInfoOptional.email"]) + + // Observed + user["observed"] = 10 + + // Computed + user["computed"] = 100 + XCTAssertNil(user["computed"]) + } + + func test_class() { + var user = UserClass() + test_keyValueCoding(&user, kind: .class) + + // Existential + /* + var p: UserProtocol = user + swift_setValue(777, to: &p, key: "id") + XCTAssert(swift_value(of: &p, key: "id") as? Int == 777) + */ + } + + func test_class_inheritance() { + var user = UserClass2() + test_keyValueCoding(&user, kind: .class, propertiesCount: 10) + + user["id"] = 100 + user["name"] = "Jack" + XCTAssert(user["id"] as? Int == 100) + XCTAssert(user["name"] as? String == "Jack") + + // Private + user["promoCode"] = 100 + XCTAssert(user["promoCode"] as? Int == 100) + } + + func test_class_objc() { + var user = UserClassObjC() + test_keyValueCoding(&user, kind: .class) + } + + func test_struct() { + var user = UserStruct() + test_keyValueCoding(&user, kind: .struct) + + // Existential + /* + var p: UserProtocol = user + swift_setValue(777, to: &p, key: "id") + XCTAssert(swift_value(of: &p, key: "id") as? Int == 777) + */ + + var song: SongProtocol = Song(name: "") + swift_setValue("Blue Suede Shoes", to: &song, key: "name") + XCTAssert(swift_value(of: &song, key: "name") as? String == "Blue Suede Shoes") + } + + func test_optional() { + var optional: UserClass? = UserClass() + test_keyValueCoding(&optional!, kind: .class) + + optional?["id"] = 123 + XCTAssert(optional?["id"] as? Int == 123) + XCTAssert(optional?.value(key: "id") as? Int == 123) + XCTAssert(swift_value(of: &optional!, key: "id") as? Int == 123) + + XCTAssertNil(swift_value(of: &optional, key: "id")) + } }