diff --git a/Example/calayer-ws/calayer-ws.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Example/calayer-ws/calayer-ws.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 0be895a..a8f8424 100644 --- a/Example/calayer-ws/calayer-ws.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Example/calayer-ws/calayer-ws.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/p-x9/IndirectlyCodable.git", "state" : { - "revision" : "81bfc339dde53a3739f82517dbef0e4cac1d9cc3", - "version" : "0.0.1" + "revision" : "548af634dc3277a5448ea9801b206c0037185f1e", + "version" : "0.1.0" } }, { @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/p-x9/KeyPathValue.git", "state" : { - "revision" : "6aeb41d6c5564ae1f18e8b7a4bc5733d739558e3", - "version" : "0.0.1" + "revision" : "8938b8f8d74a70c6b2d6a94b02e7d5753eb001db", + "version" : "0.1.0" } }, { diff --git a/Example/calayer-ws/calayer-ws/AppDelegate.swift b/Example/calayer-ws/calayer-ws/AppDelegate.swift index f012c21..3f7a715 100644 --- a/Example/calayer-ws/calayer-ws/AppDelegate.swift +++ b/Example/calayer-ws/calayer-ws/AppDelegate.swift @@ -11,8 +11,6 @@ import UIKit @main class AppDelegate: UIResponder, UIApplicationDelegate { - - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true @@ -32,6 +30,4 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // Use this method to release any resources that were specific to the discarded scenes, as they will not return. } - } - diff --git a/Example/calayer-ws/calayer-ws/SceneDelegate.swift b/Example/calayer-ws/calayer-ws/SceneDelegate.swift index ee61af4..040ff91 100644 --- a/Example/calayer-ws/calayer-ws/SceneDelegate.swift +++ b/Example/calayer-ws/calayer-ws/SceneDelegate.swift @@ -12,7 +12,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. @@ -48,6 +47,4 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // to restore the scene back to its current state. } - } - diff --git a/Package.resolved b/Package.resolved index 0be895a..a8f8424 100644 --- a/Package.resolved +++ b/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/p-x9/IndirectlyCodable.git", "state" : { - "revision" : "81bfc339dde53a3739f82517dbef0e4cac1d9cc3", - "version" : "0.0.1" + "revision" : "548af634dc3277a5448ea9801b206c0037185f1e", + "version" : "0.1.0" } }, { @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/p-x9/KeyPathValue.git", "state" : { - "revision" : "6aeb41d6c5564ae1f18e8b7a4bc5733d739558e3", - "version" : "0.0.1" + "revision" : "8938b8f8d74a70c6b2d6a94b02e7d5753eb001db", + "version" : "0.1.0" } }, { diff --git a/Package.swift b/Package.swift index 48b30f1..b20c19c 100644 --- a/Package.swift +++ b/Package.swift @@ -12,11 +12,11 @@ let package = Package( .library( name: "SDCALayer", targets: ["SDCALayer"] - ), + ) ], dependencies: [ - .package(url: "https://github.com/p-x9/IndirectlyCodable.git", .upToNextMinor(from: "0.0.1")), - .package(url: "https://github.com/p-x9/KeyPathValue.git", .upToNextMinor(from: "0.0.1")), + .package(url: "https://github.com/p-x9/IndirectlyCodable.git", from: "0.1.0"), + .package(url: "https://github.com/p-x9/KeyPathValue.git", from: "0.1.0"), .package(url: "https://github.com/jpsim/Yams.git", from: "5.0.1") ], targets: [ @@ -31,6 +31,6 @@ let package = Package( .testTarget( name: "SDCALayerTests", dependencies: ["SDCALayer"] - ), + ) ] ) diff --git a/README.md b/README.md index e53c570..f5b16c5 100644 --- a/README.md +++ b/README.md @@ -145,8 +145,8 @@ class JAALayer: JCALayer { // apply properties to model from target // targe -> model - public override func reverseApplyProperties(with target: CALayer) { - super.reverseApplyProperties(with: target) + public override func applyProperties(with target: CALayer) { + super.applyProperties(with: target) guard let target = target as? AALayer else { return } diff --git a/Sources/SDCALayer/Extension/CATransform3D+.swift b/Sources/SDCALayer/Extension/CATransform3D+.swift index 218e7fc..3420203 100644 --- a/Sources/SDCALayer/Extension/CATransform3D+.swift +++ b/Sources/SDCALayer/Extension/CATransform3D+.swift @@ -10,7 +10,10 @@ import QuartzCore extension CATransform3D: Codable { private enum CodingKeys: String, CodingKey { - case m11, m12, m13, m14, m21, m22, m23, m24, m31, m32, m33, m34, m41, m42, m43, m44 + case m11, m12, m13, m14 + case m21, m22, m23, m24 + case m31, m32, m33, m34 + case m41, m42, m43, m44 } public func encode(to encoder: Encoder) throws { diff --git a/Sources/SDCALayer/Extension/Codable+.swift b/Sources/SDCALayer/Extension/Codable+.swift index 08a3bbb..2b4db54 100644 --- a/Sources/SDCALayer/Extension/Codable+.swift +++ b/Sources/SDCALayer/Extension/Codable+.swift @@ -22,7 +22,7 @@ extension Encodable { return encoder } - var jsonString: String? { + var jsonString: String? { guard let data = try? Self.jsonEncoder.encode(self) else { return nil } diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CAGradientLayer+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CAGradientLayer+ICodable.swift index bb84c93..56728d5 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CAGradientLayer+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CAGradientLayer+ICodable.swift @@ -9,17 +9,13 @@ import QuartzCore extension CAGradientLayer { - public typealias Target = JCAGradientLayer + public typealias Model = JCAGradientLayer open override class var codableTypeName: String { - String(reflecting: Target.self) + String(reflecting: Model.self) } } -extension CAGradientLayerType: IndirectlyCodable { - public typealias Target = JCAGradientLayerType - - public func codable() -> JCAGradientLayerType? { - .init(with: self) - } +extension CAGradientLayerType: RawIndirectlyCodable { + public typealias Model = JCAGradientLayerType } diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CALayer+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CALayer+ICodable.swift index 45e4c0b..156b3e5 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CALayer+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CALayer+ICodable.swift @@ -9,7 +9,7 @@ import QuartzCore extension CALayer: IndirectlyCodable { - public typealias Target = JCALayer + public typealias Model = JCALayer public func codable() -> JCALayer? { guard let layerClass = NSClassFromString(Self.codableTypeName) as? JCALayer.Type else { @@ -21,22 +21,31 @@ extension CALayer: IndirectlyCodable { @objc open class var codableTypeName: String { - String(reflecting: Target.self) + String(reflecting: Model.self) } } -extension CALayerCornerCurve: IndirectlyCodable { - public typealias Target = JCALayerCornerCurve +extension CALayerCornerCurve: RawIndirectlyCodable { + public typealias Model = JCALayerCornerCurve +} - public func codable() -> JCALayerCornerCurve? { - .init(with: self) - } +extension CACornerMask: RawIndirectlyCodable { + public typealias Model = JCACornerMask } -extension CACornerMask: IndirectlyCodable { - public typealias Target = JCACornerMask +extension CALayerContentsGravity: RawIndirectlyCodable { + public typealias Model = JCALayerContentsGravity +} - public func codable() -> JCACornerMask? { - .init(with: self) - } +extension CALayerContentsFormat: RawIndirectlyCodable { + public typealias Model = JCALayerContentsFormat } + +extension CALayerContentsFilter: RawIndirectlyCodable { + public typealias Model = JCALayerContentsFilter +} + +extension CAEdgeAntialiasingMask: RawIndirectlyCodable { + public typealias Model = JCAEdgeAntialiasingMask +} + diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CAScrollLayer+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CAScrollLayer+ICodable.swift index eacced6..c2160b8 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CAScrollLayer+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CAScrollLayer+ICodable.swift @@ -9,17 +9,13 @@ import QuartzCore extension CAScrollLayer { - public typealias Target = JCAScrollLayer + public typealias Model = JCAScrollLayer open override class var codableTypeName: String { - String(reflecting: Target.self) + String(reflecting: Model.self) } } -extension CAScrollLayerScrollMode: IndirectlyCodable { - public typealias Target = JCAScrollLayerScrollMode - - public func codable() -> JCAScrollLayerScrollMode? { - .init(with: self) - } +extension CAScrollLayerScrollMode: RawIndirectlyCodable { + public typealias Model = JCAScrollLayerScrollMode } diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CAShapeLayer+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CAShapeLayer+ICodable.swift index c274ddc..2e18e58 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CAShapeLayer+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CAShapeLayer+ICodable.swift @@ -9,33 +9,21 @@ import QuartzCore extension CAShapeLayer { - public typealias Target = JCAShapeLayer + public typealias Model = JCAShapeLayer open override class var codableTypeName: String { - String(reflecting: Target.self) + String(reflecting: Model.self) } } -extension CAShapeLayerFillRule: IndirectlyCodable { - public typealias Target = JCAShapeLayerFillRule - - public func codable() -> JCAShapeLayerFillRule? { - .init(with: self) - } +extension CAShapeLayerFillRule: RawIndirectlyCodable { + public typealias Model = JCAShapeLayerFillRule } -extension CAShapeLayerLineCap: IndirectlyCodable { - public typealias Target = JCAShapeLayerLineCap - - public func codable() -> JCAShapeLayerLineCap? { - .init(with: self) - } +extension CAShapeLayerLineCap: RawIndirectlyCodable { + public typealias Model = JCAShapeLayerLineCap } -extension CAShapeLayerLineJoin: IndirectlyCodable { - public typealias Target = JCAShapeLayerLineJoin - - public func codable() -> JCAShapeLayerLineJoin? { - .init(with: self) - } +extension CAShapeLayerLineJoin: RawIndirectlyCodable { + public typealias Model = JCAShapeLayerLineJoin } diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CATextLayer+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CATextLayer+ICodable.swift index 36d16e3..84f5750 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CATextLayer+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CATextLayer+ICodable.swift @@ -9,25 +9,17 @@ import QuartzCore extension CATextLayer { - public typealias Target = JCATextLayer + public typealias Model = JCATextLayer open override class var codableTypeName: String { - String(reflecting: Target.self) + String(reflecting: Model.self) } } -extension CATextLayerTruncationMode: IndirectlyCodable { - public typealias Target = JCATextLayerTruncationMode - - public func codable() -> JCATextLayerTruncationMode? { - .init(with: self) - } +extension CATextLayerTruncationMode: RawIndirectlyCodable { + public typealias Model = JCATextLayerTruncationMode } -extension CATextLayerAlignmentMode: IndirectlyCodable { - public typealias Target = JCATextLayerAlignmentMode - - public func codable() -> JCATextLayerAlignmentMode? { - .init(with: self) - } +extension CATextLayerAlignmentMode: RawIndirectlyCodable { + public typealias Model = JCATextLayerAlignmentMode } diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CGColor+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CGColor+ICodable.swift index c360c7d..5b1dabd 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CGColor+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CGColor+ICodable.swift @@ -9,7 +9,7 @@ import QuartzCore extension CGColor: IndirectlyCodable { - public typealias Target = JCGColor + public typealias Model = JCGColor public func applyProperties(to target: JCGColor) {} diff --git a/Sources/SDCALayer/Extension/IndirectlyCodable/CGPath+ICodable.swift b/Sources/SDCALayer/Extension/IndirectlyCodable/CGPath+ICodable.swift index 2dca2bb..c90b7a4 100644 --- a/Sources/SDCALayer/Extension/IndirectlyCodable/CGPath+ICodable.swift +++ b/Sources/SDCALayer/Extension/IndirectlyCodable/CGPath+ICodable.swift @@ -9,7 +9,7 @@ import QuartzCore extension CGPath: IndirectlyCodable { - public typealias Target = JCGPath + public typealias Model = JCGPath public func codable() -> JCGPath? { .init(with: self) diff --git a/Sources/SDCALayer/Extension/NSUIColor+.swift b/Sources/SDCALayer/Extension/NSUIColor+.swift deleted file mode 100644 index b519381..0000000 --- a/Sources/SDCALayer/Extension/NSUIColor+.swift +++ /dev/null @@ -1,38 +0,0 @@ -// -// NSUIColor+.swift -// -// -// Created by p-x9 on 2022/11/23. -// -// - -import Foundation - -extension NSUIColor { - /// rgb color code - var rgbString: String { - var red: CGFloat = -1 - var blue: CGFloat = -1 - var green: CGFloat = -1 - getRed(&red, green: &green, blue: &blue, alpha: nil) - let rgb: [CGFloat] = [red, green, blue] - return rgb.reduce(into: "") { res, value in - let intval = Int(round(value * 255)) - res += (NSString(format: "%02X", intval) as String) - } - } - - /// rgba color code - var rgbaString: String { - var red: CGFloat = -1 - var blue: CGFloat = -1 - var green: CGFloat = -1 - var alpha: CGFloat = 1 - getRed(&red, green: &green, blue: &blue, alpha: &alpha) - let rgba: [CGFloat] = [red, green, blue, alpha] - return rgba.reduce(into: "") { res, value in - let intval = Int(round(value * 255)) - res += (NSString(format: "%02X", intval) as String) - } - } -} diff --git a/Sources/SDCALayer/Model/JCGColor.swift b/Sources/SDCALayer/Model/JCGColor.swift index 2c6fe2f..12c78e6 100644 --- a/Sources/SDCALayer/Model/JCGColor.swift +++ b/Sources/SDCALayer/Model/JCGColor.swift @@ -9,7 +9,7 @@ import Foundation import QuartzCore -public class JCGColor: ObjectConvertiblyCodable { +public class JCGColor: IndirectlyCodableModel { public typealias Target = CGColor public let code: String? diff --git a/Sources/SDCALayer/Model/JCGPath.swift b/Sources/SDCALayer/Model/JCGPath.swift index 4705c0e..7a629ad 100644 --- a/Sources/SDCALayer/Model/JCGPath.swift +++ b/Sources/SDCALayer/Model/JCGPath.swift @@ -8,7 +8,7 @@ import CoreGraphics -public class JCGPath: ObjectConvertiblyCodable { +public class JCGPath: IndirectlyCodableModel { public typealias Target = CGPath public var pathElements: [JCGPathElement]? @@ -29,7 +29,7 @@ public class JCGPath: ObjectConvertiblyCodable { .filter { let isValid = $0.elementType != nil && $0.elementType!.numberOfPoints <= $0.points.count if !isValid { - print("⚠️[warning] SDCALayer invalid path element") + print("⚠️ [SDCALayer] invalid path element") } return isValid } @@ -57,7 +57,6 @@ public class JCGPath: ObjectConvertiblyCodable { } } - public struct JCGPathElement: Codable { public var type: String public var points: [CGPoint] diff --git a/Sources/SDCALayer/Model/Layer/JCAGradientLayer.swift b/Sources/SDCALayer/Model/Layer/JCAGradientLayer.swift index 5769453..cb6bec9 100644 --- a/Sources/SDCALayer/Model/Layer/JCAGradientLayer.swift +++ b/Sources/SDCALayer/Model/Layer/JCAGradientLayer.swift @@ -1,9 +1,9 @@ // // JCAGradientLayer.swift -// +// // // Created by p-x9 on 2022/11/11. -// +// // import Foundation @@ -14,26 +14,24 @@ open class JCAGradientLayer: JCALayer { public typealias Target = CAGradientLayer private enum CodingKeys: String, CodingKey { - case colors, locations, startPoint, endPoint, type + case colors + case locations + case startPoint + case endPoint + case type } open override class var targetTypeName: String { String(reflecting: Target.self) } - static private let propertyMap: PropertyMap = [ - \.colors: .init(\.colors), - \.startPoint: .init(\.startPoint), - \.endPoint: .init(\.endPoint), - \.type: .init(\.type) - ] - - static private let reversePropertyMap: PropertyMap = [ - \.colors: .init(\.colors), - \.startPoint: .init(\.startPoint), - \.endPoint: .init(\.endPoint), - \.type: .init(\.type) - ] + static private let propertyMap: PropertyMap = .init([ +// .init(\.colors, \.colors), // handle manually +// .init(\.locations, \.locations), // handle manually + .init(\.startPoint, \.startPoint), + .init(\.endPoint, \.endPoint), + .init(\.type, \.type) + ]) public var colors: [JCGColor]? public var locations: [Double]? @@ -64,7 +62,7 @@ open class JCAGradientLayer: JCALayer { public required convenience init(with object: CALayer) { self.init() - reverseApplyProperties(with: object) + applyProperties(with: object) } open override func encode(to encoder: Encoder) throws { @@ -88,16 +86,30 @@ open class JCAGradientLayer: JCALayer { Self.propertyMap.apply(to: target, from: self) + target.colors = colors? + .compactMap { + $0.converted() + } target.locations = locations?.map { NSNumber(floatLiteral: $0) } } - open override func reverseApplyProperties(with target: CALayer) { - super.reverseApplyProperties(with: target) + open override func applyProperties(with target: CALayer) { + super.applyProperties(with: target) guard let target = target as? CAGradientLayer else { return } - Self.reversePropertyMap.apply(to: self, from: target) - + Self.propertyMap.apply(to: self, from: target) + + self.colors = target.colors? + .filter { + CFGetTypeID($0 as AnyObject) == CGColor.typeID + } + .map { + $0 as! CGColor + } + .compactMap { + $0.codable() + } self.locations = target.locations?.map { $0.doubleValue } } @@ -110,17 +122,11 @@ open class JCAGradientLayer: JCALayer { } } -public class JCAGradientLayerType: ObjectConvertiblyCodable { +public final class JCAGradientLayerType: RawIndirectlyCodableModel { public typealias Target = CAGradientLayerType - public var rawValue: String? - - required public init(with object: CAGradientLayerType) { - rawValue = object.rawValue - } - - public func converted() -> CAGradientLayerType? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } diff --git a/Sources/SDCALayer/Model/Layer/JCALayer.swift b/Sources/SDCALayer/Model/Layer/JCALayer.swift index 4df270b..8aa2e4d 100644 --- a/Sources/SDCALayer/Model/Layer/JCALayer.swift +++ b/Sources/SDCALayer/Model/Layer/JCALayer.swift @@ -1,9 +1,9 @@ // // JCALayer.swift -// +// // // Created by p-x9 on 2022/11/06. -// +// // import Foundation @@ -17,78 +17,58 @@ open class JCALayer: CALayerConvertible, Codable { String(reflecting: Target.self) } - static private let propertyMap: PropertyMap = [ - \.bounds: .init(\.bounds), - \.position: .init(\.position), - \.zPosition: .init(\.zPosition), - \.anchorPoint: .init(\.anchorPoint), - \.anchorPointZ: .init(\.anchorPointZ), - \.transform: .init(\.transform), - \.frame: .init(\.frame), - \.isHidden: .init(\.isHidden), - \.isDoubleSided: .init(\.isDoubleSided), - \.isGeometryFlipped: .init(\.isGeometryFlipped), - \.sublayerTransform: .init(\.sublayerTransform), - \.mask: .init(\.mask), - \.masksToBounds: .init(\.masksToBounds), - \.isOpaque: .init(\.isOpaque), - \.needsDisplayOnBoundsChange: .init(\.needsDisplayOnBoundsChange), - \.drawsAsynchronously: .init(\.drawsAsynchronously), - \.allowsEdgeAntialiasing: .init(\.allowsEdgeAntialiasing), - \.backgroundColor: .init(\.backgroundColor), - \.cornerRadius: .init(\.cornerRadius), - \.maskedCorners: .init(\.maskedCorners), - \.cornerCurve: .init(\.cornerCurve), - \.borderWidth: .init(\.borderWidth), - \.borderColor: .init(\.borderColor), - \.opacity: .init(\.opacity), - \.allowsGroupOpacity: .init(\.allowsGroupOpacity), - \.shouldRasterize: .init(\.shouldRasterize), - \.rasterizationScale: .init(\.rasterizationScale), - \.shadowColor: .init(\.shadowColor), - \.shadowOpacity: .init(\.shadowOpacity), - \.shadowOffset: .init(\.shadowOffset), - \.shadowRadius: .init(\.shadowRadius), - \.shadowPath: .init(\.shadowPath), - \.name: .init(\.name) - ] - - static private let reversePropertyMap: PropertyMap = [ - \.bounds: .init(\.bounds), - \.position: .init(\.position), - \.zPosition: .init(\.zPosition), - \.anchorPoint: .init(\.anchorPoint), - \.anchorPointZ: .init(\.anchorPointZ), - \.transform: .init(\.transform), - \.frame: .init(\.frame), - \.isHidden: .init(\.isHidden), - \.isDoubleSided: .init(\.isDoubleSided), - \.isGeometryFlipped: .init(\.isGeometryFlipped), - \.sublayerTransform: .init(\.sublayerTransform), - \.mask: .init(\.mask), - \.masksToBounds: .init(\.masksToBounds), - \.isOpaque: .init(\.isOpaque), - \.needsDisplayOnBoundsChange: .init(\.needsDisplayOnBoundsChange), - \.drawsAsynchronously: .init(\.drawsAsynchronously), - \.allowsEdgeAntialiasing: .init(\.allowsEdgeAntialiasing), - \.backgroundColor: .init(\.backgroundColor), - \.cornerRadius: .init(\.cornerRadius), - \.maskedCorners: .init(\.maskedCorners), - \.cornerCurve: .init(\.cornerCurve), - \.borderWidth: .init(\.borderWidth), - \.borderColor: .init(\.borderColor), - \.opacity: .init(\.opacity), - \.allowsGroupOpacity: .init(\.allowsGroupOpacity), - \.shouldRasterize: .init(\.shouldRasterize), - \.rasterizationScale: .init(\.rasterizationScale), - \.shadowColor: .init(\.shadowColor), - \.shadowOpacity: .init(\.shadowOpacity), - \.shadowOffset: .init(\.shadowOffset), - \.shadowRadius: .init(\.shadowRadius), - \.shadowPath: .init(\.shadowPath), - \.name: .init(\.name), - \.sublayers: .init(\.sublayers) - ] + static private let propertyMap: PropertyMap = .init([ + .init(\.bounds, \.bounds), + .init(\.position, \.position), + .init(\.zPosition, \.zPosition), + .init(\.anchorPoint, \.anchorPoint), + .init(\.anchorPointZ, \.anchorPointZ), + .init(\.transform, \.transform), + .init(\.frame, \.frame), + .init(\.isHidden, \.isHidden), + .init(\.isDoubleSided, \.isDoubleSided), + .init(\.isGeometryFlipped, \.isGeometryFlipped), +// .init(\.sublayers, \.sublayers), // handle manually + .init(\.sublayerTransform, \.sublayerTransform), +// .init(\.mask, \.mask), // handle manually + .init(\.masksToBounds, \.masksToBounds), +// .init(\.contents, \.contents), + .init(\.contentsRect, \.contentsRect), + .init(\.contentsGravity, \.contentsGravity), + .init(\.contentsScale, \.contentsScale), + .init(\.contentsCenter, \.contentsCenter), + .init(\.contentsFormat, \.contentsFormat), +// .init(\.wantsExtendedDynamicRangeContent, \.wantsExtendedDynamicRangeContent), + .init(\.minificationFilter, \.minificationFilter), + .init(\.magnificationFilter, \.magnificationFilter), + .init(\.minificationFilterBias, \.minificationFilterBias), + .init(\.isOpaque, \.isOpaque), + .init(\.needsDisplayOnBoundsChange, \.needsDisplayOnBoundsChange), + .init(\.drawsAsynchronously, \.drawsAsynchronously), + .init(\.edgeAntialiasingMask, \.edgeAntialiasingMask), + .init(\.allowsEdgeAntialiasing, \.allowsEdgeAntialiasing), + .init(\.backgroundColor, \.backgroundColor), + .init(\.cornerRadius, \.cornerRadius), + .init(\.maskedCorners, \.maskedCorners), + .init(\.cornerCurve, \.cornerCurve), + .init(\.borderWidth, \.borderWidth), + .init(\.borderColor, \.borderColor), + .init(\.opacity, \.opacity), + .init(\.allowsGroupOpacity, \.allowsGroupOpacity), +// .init(\.compositingFilter, \.compositingFilter), +// .init(\.filters, \.filters), +// .init(\.backgroundFilters, \.backgroundFilters), + .init(\.shouldRasterize, \.shouldRasterize), + .init(\.rasterizationScale, \.rasterizationScale), + .init(\.shadowColor, \.shadowColor), + .init(\.shadowOpacity, \.shadowOpacity), + .init(\.shadowOffset, \.shadowOffset), + .init(\.shadowRadius, \.shadowRadius), + .init(\.shadowPath, \.shadowPath), +// .init(\.actions, \.actions), + .init(\.name, \.name), +// .init(\.style, \.style) + ]) public var bounds: CGRect? public var position: CGPoint? @@ -112,12 +92,24 @@ open class JCALayer: CALayerConvertible, Codable { public var mask: SDCALayer? public var masksToBounds: Bool? + public var contentsRect: CGRect? + public var contentsGravity: JCALayerContentsGravity? + public var contentsScale: CGFloat? + public var contentsCenter: CGRect? + public var contentsFormat: JCALayerContentsFormat? + +// public var wantsExtendedDynamicRangeContent: Bool? + public var minificationFilter: JCALayerContentsFilter? + public var magnificationFilter: JCALayerContentsFilter? + public var minificationFilterBias: Float? + public var isOpaque: Bool? public var needsDisplayOnBoundsChange: Bool? public var drawsAsynchronously: Bool? + public var edgeAntialiasingMask: JCAEdgeAntialiasingMask? public var allowsEdgeAntialiasing: Bool? public var backgroundColor: JCGColor? @@ -150,20 +142,21 @@ open class JCALayer: CALayerConvertible, Codable { public required convenience init(with object: CALayer) { self.init() - reverseApplyProperties(with: object) + applyProperties(with: object) } open func applyProperties(to target: CALayer) { Self.propertyMap.apply(to: target, from: self) + target.mask = mask?.convertToLayer() sublayers?.compactMap { $0.convertToLayer() } .forEach { target.addSublayer($0) } } - open func reverseApplyProperties(with target: CALayer) { - Self.reversePropertyMap.apply(to: self, from: target) + open func applyProperties(with target: CALayer) { + Self.propertyMap.apply(to: self, from: target) self.mask = SDCALayer(model: target.mask?.codable()) self.sublayers = target.sublayers?.compactMap { @@ -180,33 +173,56 @@ open class JCALayer: CALayerConvertible, Codable { } } -public class JCALayerCornerCurve: ObjectConvertiblyCodable { +public final class JCALayerCornerCurve: RawIndirectlyCodableModel { public typealias Target = CALayerCornerCurve - public var rawValue: String? + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue + } +} + +public final class JCACornerMask: RawIndirectlyCodableModel { + public typealias Target = CACornerMask - required public init(with object: CALayerCornerCurve) { - rawValue = object.rawValue + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } +} + +public final class JCALayerContentsGravity: RawIndirectlyCodableModel { + public typealias Target = CALayerContentsGravity - public func converted() -> CALayerCornerCurve? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } +public final class JCALayerContentsFormat: RawIndirectlyCodableModel { + public typealias Target = CALayerContentsFormat -public class JCACornerMask: ObjectConvertiblyCodable { - public typealias Target = CACornerMask + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue + } +} - public var rawValue: UInt? +public final class JCALayerContentsFilter: RawIndirectlyCodableModel { + public typealias Target = CALayerContentsFilter - required public init(with object: CACornerMask) { - rawValue = object.rawValue + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } +} + +public final class JCAEdgeAntialiasingMask: RawIndirectlyCodableModel { + public typealias Target = CAEdgeAntialiasingMask - public func converted() -> CACornerMask? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } diff --git a/Sources/SDCALayer/Model/Layer/JCAScrollLayer.swift b/Sources/SDCALayer/Model/Layer/JCAScrollLayer.swift index 505a905..5a6ab6f 100644 --- a/Sources/SDCALayer/Model/Layer/JCAScrollLayer.swift +++ b/Sources/SDCALayer/Model/Layer/JCAScrollLayer.swift @@ -38,7 +38,7 @@ open class JCAScrollLayer: JCALayer { public required convenience init(with object: CALayer) { self.init() - reverseApplyProperties(with: object) + applyProperties(with: object) } open override func encode(to encoder: Encoder) throws { @@ -59,8 +59,8 @@ open class JCAScrollLayer: JCALayer { } } - open override func reverseApplyProperties(with target: CALayer) { - super.reverseApplyProperties(with: target) + open override func applyProperties(with target: CALayer) { + super.applyProperties(with: target) guard let target = target as? CAScrollLayer else { return } @@ -76,17 +76,11 @@ open class JCAScrollLayer: JCALayer { } } -public class JCAScrollLayerScrollMode: ObjectConvertiblyCodable { +public final class JCAScrollLayerScrollMode: RawIndirectlyCodableModel { public typealias Target = CAScrollLayerScrollMode - public var rawValue: String? - - required public init(with object: CAScrollLayerScrollMode) { - rawValue = object.rawValue - } - - public func converted() -> CAScrollLayerScrollMode? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } diff --git a/Sources/SDCALayer/Model/Layer/JCAShapeLayer.swift b/Sources/SDCALayer/Model/Layer/JCAShapeLayer.swift index e6f31e4..2c0f392 100644 --- a/Sources/SDCALayer/Model/Layer/JCAShapeLayer.swift +++ b/Sources/SDCALayer/Model/Layer/JCAShapeLayer.swift @@ -14,40 +14,38 @@ open class JCAShapeLayer: JCALayer { typealias Target = CAShapeLayer private enum CodingKeys: String, CodingKey { - case path, fillColor, fillRule, strokeColor, strokeStart, strokeEnd, lineWidth, miterLimit, lineCap, lineJoin, lineDashPhase, lineDashPattern + case path + case fillColor + case fillRule + case strokeColor + case strokeStart + case strokeEnd + case lineWidth + case miterLimit + case lineCap + case lineJoin + case lineDashPhase + case lineDashPattern } open override class var targetTypeName: String { String(reflecting: Target.self) } - static private let propertyMap: PropertyMap = [ - \.path: .init(\.path), - \.fillColor: .init(\.fillColor), - \.fillRule: .init(\.fillRule), - \.strokeColor: .init(\.strokeColor), - \.strokeStart: .init(\.strokeStart), - \.strokeEnd: .init(\.strokeEnd), - \.lineWidth: .init(\.lineWidth), - \.miterLimit: .init(\.miterLimit), - \.lineCap: .init(\.lineCap), - \.lineJoin: .init(\.lineJoin), - \.lineDashPhase: .init(\.lineDashPhase) - ] - - static private let reversePropertyMap: PropertyMap = [ - \.path: .init(\.path), - \.fillColor: .init(\.fillColor), - \.fillRule: .init(\.fillRule), - \.strokeColor: .init(\.strokeColor), - \.strokeStart: .init(\.strokeStart), - \.strokeEnd: .init(\.strokeEnd), - \.lineWidth: .init(\.lineWidth), - \.miterLimit: .init(\.miterLimit), - \.lineCap: .init(\.lineCap), - \.lineJoin: .init(\.lineJoin), - \.lineDashPhase: .init(\.lineDashPhase) - ] + static private let propertyMap: PropertyMap = .init([ + .init(\.path, \.path), + .init(\.fillColor, \.fillColor), + .init(\.fillRule, \.fillRule), + .init(\.strokeColor, \.strokeColor), + .init(\.strokeStart, \.strokeStart), + .init(\.strokeEnd, \.strokeEnd), + .init(\.lineWidth, \.lineWidth), + .init(\.miterLimit, \.miterLimit), + .init(\.lineCap, \.lineCap), + .init(\.lineJoin, \.lineJoin), + .init(\.lineDashPhase, \.lineDashPhase), +// .init(\.lineDashPattern, \.lineDashPattern) + ]) public var path: JCGPath? @@ -103,7 +101,7 @@ open class JCAShapeLayer: JCALayer { public required convenience init(with object: CALayer) { self.init() - reverseApplyProperties(with: object) + applyProperties(with: object) } open override func encode(to encoder: Encoder) throws { @@ -142,12 +140,12 @@ open class JCAShapeLayer: JCALayer { target.lineDashPattern = lineDashPattern?.map { NSNumber(floatLiteral: $0) } } - open override func reverseApplyProperties(with target: CALayer) { - super.reverseApplyProperties(with: target) + open override func applyProperties(with target: CALayer) { + super.applyProperties(with: target) guard let target = target as? CAShapeLayer else { return } - Self.reversePropertyMap.apply(to: self, from: target) + Self.propertyMap.apply(to: self, from: target) self.lineDashPattern = target.lineDashPattern?.map { $0.doubleValue } } @@ -161,47 +159,29 @@ open class JCAShapeLayer: JCALayer { } } -public class JCAShapeLayerFillRule: ObjectConvertiblyCodable { +public final class JCAShapeLayerFillRule: RawIndirectlyCodableModel { public typealias Target = CAShapeLayerFillRule - public var rawValue: String? - - required public init(with object: CAShapeLayerFillRule) { - rawValue = object.rawValue - } - - public func converted() -> CAShapeLayerFillRule? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } -public class JCAShapeLayerLineCap: ObjectConvertiblyCodable { +public final class JCAShapeLayerLineCap: RawIndirectlyCodableModel { public typealias Target = CAShapeLayerLineCap - public var rawValue: String? - - required public init(with object: CAShapeLayerLineCap) { - rawValue = object.rawValue - } - - public func converted() -> CAShapeLayerLineCap? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } -public class JCAShapeLayerLineJoin: ObjectConvertiblyCodable { +public final class JCAShapeLayerLineJoin: RawIndirectlyCodableModel { public typealias Target = CAShapeLayerLineJoin - public var rawValue: String? - - required public init(with object: CAShapeLayerLineJoin) { - rawValue = object.rawValue - } - - public func converted() -> CAShapeLayerLineJoin? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } diff --git a/Sources/SDCALayer/Model/Layer/JCATextLayer.swift b/Sources/SDCALayer/Model/Layer/JCATextLayer.swift index c24dff2..dea63f4 100644 --- a/Sources/SDCALayer/Model/Layer/JCATextLayer.swift +++ b/Sources/SDCALayer/Model/Layer/JCATextLayer.swift @@ -1,9 +1,9 @@ // // JCATextLayer.swift -// +// // // Created by p-x9 on 2022/11/14. -// +// // import Foundation @@ -15,34 +15,30 @@ open class JCATextLayer: JCALayer { typealias Target = CATextLayer private enum CodingKeys: String, CodingKey { - case string, font, fontSize, foregroundColor, isWrapped, truncationMode, alignmentMode, allowsFontSubpixelQuantization + case string + case font + case fontSize + case foregroundColor + case isWrapped + case truncationMode + case alignmentMode + case allowsFontSubpixelQuantization } open override class var targetTypeName: String { String(reflecting: Target.self) } - static private let propertyMap: PropertyMap = [ - \.string: .init(\.string), - \.font: .init(\.font), - \.fontSize: .init(\.fontSize), - \.foregroundColor: .init(\.foregroundColor), - \.isWrapped: .init(\.isWrapped), - \.truncationMode: .init(\.truncationMode), - \.alignmentMode: .init(\.alignmentMode), - \.allowsFontSubpixelQuantization: .init(\.allowsFontSubpixelQuantization) - ] - - static private let reversePropertyMap: PropertyMap = [ - \.string: .init(\.string), -// \.font: .init(\.font), - \.fontSize: .init(\.fontSize), - \.foregroundColor: .init(\.foregroundColor), - \.isWrapped: .init(\.isWrapped), - \.truncationMode: .init(\.truncationMode), - \.alignmentMode: .init(\.alignmentMode), - \.allowsFontSubpixelQuantization: .init(\.allowsFontSubpixelQuantization) - ] + static private let propertyMap: PropertyMap = .init([ +// .init(\.string, \.string), // handle manually +// .init(\.font, \.font), // handle manually + .init(\.fontSize, \.fontSize), + .init(\.foregroundColor, \.foregroundColor), + .init(\.isWrapped, \.isWrapped), + .init(\.truncationMode, \.truncationMode), + .init(\.alignmentMode, \.alignmentMode), + .init(\.allowsFontSubpixelQuantization, \.allowsFontSubpixelQuantization) + ]) public var string: String? @@ -88,7 +84,7 @@ open class JCATextLayer: JCALayer { public required convenience init(with object: CALayer) { self.init() - reverseApplyProperties(with: object) + applyProperties(with: object) } open override func encode(to encoder: Encoder) throws { @@ -118,15 +114,19 @@ open class JCATextLayer: JCALayer { guard let target = target as? CATextLayer else { return } Self.propertyMap.apply(to: target, from: self) + + target.string = string + target.font = font as? CFTypeRef } - open override func reverseApplyProperties(with target: CALayer) { - super.reverseApplyProperties(with: target) + open override func applyProperties(with target: CALayer) { + super.applyProperties(with: target) guard let target = target as? CATextLayer else { return } - Self.reversePropertyMap.apply(to: self, from: target) + Self.propertyMap.apply(to: self, from: target) + self.string = target.string as? String if let font = target[keyPath: \.font] { switch CFGetTypeID(font) { case CFStringGetTypeID(): @@ -150,32 +150,20 @@ open class JCATextLayer: JCALayer { } } -public class JCATextLayerTruncationMode: ObjectConvertiblyCodable { +public final class JCATextLayerTruncationMode: RawIndirectlyCodableModel { public typealias Target = CATextLayerTruncationMode - public var rawValue: String? - - required public init(with object: CATextLayerTruncationMode) { - rawValue = object.rawValue - } - - public func converted() -> CATextLayerTruncationMode? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } -public class JCATextLayerAlignmentMode: ObjectConvertiblyCodable { +public final class JCATextLayerAlignmentMode: RawIndirectlyCodableModel { public typealias Target = CATextLayerAlignmentMode - public var rawValue: String? - - required public init(with object: CATextLayerAlignmentMode) { - rawValue = object.rawValue - } - - public func converted() -> CATextLayerAlignmentMode? { - guard let rawValue else { return nil } - return .init(rawValue: rawValue) + public var rawValue: Target.RawValue + public required init(rawValue: Target.RawValue) { + self.rawValue = rawValue } } diff --git a/Sources/SDCALayer/Protocol/CALayerConvertible.swift b/Sources/SDCALayer/Protocol/CALayerConvertible.swift index 2abd7e0..3868782 100644 --- a/Sources/SDCALayer/Protocol/CALayerConvertible.swift +++ b/Sources/SDCALayer/Protocol/CALayerConvertible.swift @@ -8,7 +8,7 @@ import Foundation -public protocol CALayerConvertible: ObjectConvertiblyCodable { +public protocol CALayerConvertible: IndirectlyCodableModel { func convertToLayer() -> Target? } diff --git a/Sources/SDCALayer/Protocol/OptionalType.swift b/Sources/SDCALayer/Protocol/OptionalType.swift new file mode 100644 index 0000000..2f2d378 --- /dev/null +++ b/Sources/SDCALayer/Protocol/OptionalType.swift @@ -0,0 +1,19 @@ +// +// OptionalType.swift +// +// +// Created by p-x9 on 2024/04/03. +// +// + +import Foundation + +public protocol OptionalType { + associatedtype Wrapped + + var wrapped: Wrapped? { get } +} + +extension Optional: OptionalType { + public var wrapped: Wrapped? { self } +} diff --git a/Sources/SDCALayer/Protocol/RawIndirectlyCodable.swift b/Sources/SDCALayer/Protocol/RawIndirectlyCodable.swift new file mode 100644 index 0000000..1fd8e57 --- /dev/null +++ b/Sources/SDCALayer/Protocol/RawIndirectlyCodable.swift @@ -0,0 +1,40 @@ +// +// RawIndirectlyCodable.swift +// +// +// Created by p-x9 on 2024/04/04. +// +// + +import Foundation +import IndirectlyCodable + +public protocol RawIndirectlyCodable: RawRepresentable & IndirectlyCodable where RawValue: Codable, Model: RawIndirectlyCodableModel, Model.Target == Self {} + +public protocol RawIndirectlyCodableModel: IndirectlyCodableModel where Target: RawIndirectlyCodable, Target.Model == Self { + var rawValue: Target.RawValue { get } + init(rawValue: Target.RawValue) +} + +extension RawIndirectlyCodableModel { + public init(with target: Target) { + self.init(rawValue: target.rawValue) + } + + public func converted() -> Target? { + .init(rawValue: rawValue) + } +} +// +//extension RawIndirectlyCodableModel { +// public func encode(to encoder: Encoder) throws { +// var container = encoder.singleValueContainer() +// try container.encode(rawValue) +// } +// +// public init(from decoder: Decoder) throws { +// let container = try decoder.singleValueContainer() +// let rawValue = try container.decode(Target.RawValue.self) +// self.init(rawValue: rawValue) +// } +//} diff --git a/Sources/SDCALayer/Util/PropertyMap.swift b/Sources/SDCALayer/Util/PropertyMap.swift index 5372b37..d2c5708 100644 --- a/Sources/SDCALayer/Util/PropertyMap.swift +++ b/Sources/SDCALayer/Util/PropertyMap.swift @@ -1,49 +1,94 @@ // // PropertyMap.swift -// +// // // Created by p-x9 on 2022/11/21. -// +// // import Foundation import IndirectlyCodable import KeyPathValue -public typealias PropertyMap = Dictionary, ReferenceWritableKeyPathValueApplier> +public struct PropertyMap { + public typealias Map = [PartialKeyPath: ReferenceWritableKeyPathValueApplier] + + public typealias ForwardMap = Map + public typealias ReverseMap = Map + public let forwardMap: ForwardMap + public let reverseMap: ReverseMap +} extension PropertyMap { - /// ObjectConvertiblyCodable -> IndirectlyCodable - /// (Codable -> IndirectlyCodable) - public func apply(to target: Target, from object: Object) where Key: PartialKeyPath, Value == ReferenceWritableKeyPathValueApplier, Target: IndirectlyCodable, Object: ObjectConvertiblyCodable { - - self.forEach { keyPath, applier in - var value = object[keyPath: keyPath] - switch value { - case let v as (any ObjectConvertiblyCodable): - guard let codable = v.converted() else { return } - value = codable + public struct MappingElement { + public typealias MapElement = (PartialKeyPath, ReferenceWritableKeyPathValueApplier) - case let v as [any ObjectConvertiblyCodable]: - value = v.compactMap { $0.converted() } + public typealias ForwardMapElement = MapElement + public typealias ReverseMapElement = MapElement - default: - break - } - applier.apply(value, target) + public let forwardMapElement: ForwardMapElement + public let reverseMapElement: ReverseMapElement + + public init( + _ sourceKeyPath: ReferenceWritableKeyPath, + _ destinationKeyPath: ReferenceWritableKeyPath + ) { + forwardMapElement = (sourceKeyPath, .init(destinationKeyPath)) + reverseMapElement = (destinationKeyPath, .init(sourceKeyPath)) + } + + public init( + _ sourceKeyPath: ReferenceWritableKeyPath, + _ destinationKeyPath: ReferenceWritableKeyPath + ) { + forwardMapElement = (sourceKeyPath, .init(destinationKeyPath)) + reverseMapElement = (destinationKeyPath, .init(sourceKeyPath)) } } + + public init(_ elements: [MappingElement]) { + forwardMap = Dictionary(uniqueKeysWithValues: elements.map(\.forwardMapElement)) + reverseMap = Dictionary(uniqueKeysWithValues: elements.map(\.reverseMapElement)) + } +} + +extension PropertyMap.MappingElement { + public init( + _ sourceKeyPath: ReferenceWritableKeyPath, + _ destinationKeyPath: ReferenceWritableKeyPath + ) where SourceValue: IndirectlyCodable, DestinationValue: IndirectlyCodableModel, SourceValue.Model == DestinationValue, SourceValue == DestinationValue.Target { + forwardMapElement = (sourceKeyPath, .init(destinationKeyPath)) + reverseMapElement = (destinationKeyPath, .init(sourceKeyPath)) + } + + public init( + _ sourceKeyPath: ReferenceWritableKeyPath, + _ destinationKeyPath: ReferenceWritableKeyPath + ) where SourceValue: IndirectlyCodable, DestinationValue: IndirectlyCodableModel, SourceValue.Model == DestinationValue, SourceValue == DestinationValue.Target { + forwardMapElement = (sourceKeyPath, .init(destinationKeyPath)) + reverseMapElement = (destinationKeyPath, .init(sourceKeyPath)) + } + + public init( + _ sourceKeyPath: ReferenceWritableKeyPath, + _ destinationKeyPath: ReferenceWritableKeyPath + ) where SourceValue: Sequence, DestinationValue: Sequence, SourceValue.Element: IndirectlyCodable, DestinationValue.Element: IndirectlyCodableModel, SourceValue.Element.Model == DestinationValue.Element, SourceValue.Element == DestinationValue.Element.Target { + forwardMapElement = (sourceKeyPath, .init(destinationKeyPath)) + reverseMapElement = (destinationKeyPath, .init(sourceKeyPath)) + } } extension PropertyMap { /// IndirectlyCodable -> ObjectConvertiblyCodable /// (IndirectlyCodable -> Codable) @_disfavoredOverload - public func apply(to target: Target, from object: Object) where Key: PartialKeyPath, Value == ReferenceWritableKeyPathValueApplier, Target: ObjectConvertiblyCodable, Object: IndirectlyCodable { - - self.forEach { keyPath, applier in - var value = object[keyPath: keyPath] + public func apply( + to target: Destination, + from source: Source + ) { + forwardMap.forEach { keyPath, applier in + var value = source[keyPath: keyPath] switch value { case let v as (any IndirectlyCodable): guard let codable = v.codable() else { return } @@ -55,19 +100,69 @@ extension PropertyMap { default: break } - applier.apply(value, target) +#if DEBUG + let result = applier.apply(value, to: target) + if !result { + if let optional = (value as? (any OptionalType)), + optional.wrapped == nil { + return + } + print("⚠️ [SDCALayer] failed to assign value(\(keyPath))") + } +#else + applier.apply(value, to: target) +#endif + } + } +} + +extension PropertyMap { + /// ObjectConvertiblyCodable -> IndirectlyCodable + /// (Codable -> IndirectlyCodable) + public func apply( + to source: Source, + from destination: Destination + ) { + reverseMap.forEach { keyPath, applier in + var value = destination[keyPath: keyPath] + switch value { + case let v as (any IndirectlyCodableModel): + guard let codable = v.converted() else { return } + value = codable + + case let v as [any IndirectlyCodableModel]: + value = v.compactMap { $0.converted() } + + default: + break + } +#if DEBUG + let result = applier.apply(value, to: source) + if !result { + if let optional = (value as? (any OptionalType)), + optional.wrapped == nil { + return + } + print("⚠️ [SDCALayer] failed to assign value(\(keyPath))") + } +#else + applier.apply(value, to: source) +#endif } } } import QuartzCore + extension PropertyMap { /// CALayer -> CALayerConvertible /// (CaLayer -> Codable) - public func apply(to target: Target, from object: Object) where Key: PartialKeyPath, Value == ReferenceWritableKeyPathValueApplier, Target: ObjectConvertiblyCodable, Object: CALayer & IndirectlyCodable { - - self.forEach { keyPath, applier in - var value = object[keyPath: keyPath] + public func apply( + to target: Destination, + from source: Source + ) where Source: CALayer & IndirectlyCodable { + forwardMap.forEach { keyPath, applier in + var value = source[keyPath: keyPath] switch value { case let v as (any IndirectlyCodable): @@ -82,8 +177,19 @@ extension PropertyMap { } if let keyPath = keyPath._kvcKeyPathString, - object.shouldArchiveValue(forKey: keyPath) { - applier.apply(value, target) + source.shouldArchiveValue(forKey: keyPath) { +#if DEBUG + let result = applier.apply(value, to: target) + if !result { + if let optional = (value as? (any OptionalType)), + optional.wrapped == nil { + return + } + print("⚠️ [SDCALayer] failed to assign value(\(keyPath))") + } +#else + applier.apply(value, to: target) +#endif } } } diff --git a/Sources/SDCALayer/Util/typealias.swift b/Sources/SDCALayer/Util/typealias.swift deleted file mode 100644 index 7047c88..0000000 --- a/Sources/SDCALayer/Util/typealias.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// typealias.swift -// -// -// Created by p-x9 on 2022/11/14. -// -// - -#if canImport(UIKit) -import UIKit -typealias NSUIFont = UIFont -typealias NSUIColor = UIColor -#endif - -#if canImport(Cocoa) -import Cocoa -typealias NSUIFont = NSFont -typealias NSUIColor = NSColor -#endif -