|
14 | 14 | dynamicMember keyPath: KeyPath<Value.AllCasePaths, AnyCasePath<Value, Member>>
|
15 | 15 | ) -> Binding<Member>?
|
16 | 16 | where Value: CasePathable {
|
17 |
| - let casePath = Value.allCasePaths[keyPath: keyPath] |
18 |
| - return Binding<Member>( |
19 |
| - unwrapping: Binding<Member?>( |
20 |
| - get: { casePath.extract(from: self.wrappedValue) }, |
21 |
| - set: { newValue, transaction in |
22 |
| - guard let newValue else { return } |
23 |
| - self.transaction(transaction).wrappedValue = casePath.embed(newValue) |
24 |
| - } |
25 |
| - ) |
26 |
| - ) |
| 17 | + Binding<Member>(unwrapping: self[keyPath]) |
27 | 18 | }
|
28 | 19 |
|
29 | 20 | /// Returns a binding to the associated value of a given case key path.
|
|
36 | 27 | dynamicMember keyPath: KeyPath<Enum.AllCasePaths, AnyCasePath<Enum, Member>>
|
37 | 28 | ) -> Binding<Member?>
|
38 | 29 | where Value == Enum? {
|
39 |
| - let casePath = Enum.allCasePaths[keyPath: keyPath] |
40 |
| - return Binding<Member?>( |
41 |
| - get: { |
42 |
| - guard let wrappedValue = self.wrappedValue else { return nil } |
43 |
| - return casePath.extract(from: wrappedValue) |
44 |
| - }, |
45 |
| - set: { newValue, transaction in |
46 |
| - guard let newValue else { |
47 |
| - self.transaction(transaction).wrappedValue = nil |
48 |
| - return |
49 |
| - } |
50 |
| - self.transaction(transaction).wrappedValue = casePath.embed(newValue) |
51 |
| - } |
52 |
| - ) |
| 30 | + self[keyPath] |
53 | 31 | }
|
54 | 32 | #endif
|
55 | 33 |
|
|
68 | 46 | /// - Parameter base: A value to project to an unwrapped value.
|
69 | 47 | /// - Returns: A new binding or `nil` when `base` is `nil`.
|
70 | 48 | public init?(unwrapping base: Binding<Value?>) {
|
71 |
| - self.init(unwrapping: base, case: AnyCasePath(\.some)) |
| 49 | + guard let value = base.wrappedValue else { return nil } |
| 50 | + self = base[default: DefaultSubscript(value)] |
72 | 51 | }
|
73 | 52 |
|
74 | 53 | /// Creates a binding by projecting the current optional value to a boolean describing if it's
|
|
79 | 58 | /// - Returns: A binding to a boolean. Returns `true` if non-`nil`, otherwise `false`.
|
80 | 59 | public func isPresent<Wrapped>() -> Binding<Bool>
|
81 | 60 | where Value == Wrapped? {
|
82 |
| - .init( |
83 |
| - get: { self.wrappedValue != nil }, |
84 |
| - set: { isPresent, transaction in |
85 |
| - if !isPresent { |
86 |
| - self.transaction(transaction).wrappedValue = nil |
87 |
| - } |
88 |
| - } |
89 |
| - ) |
| 61 | + self._isPresent |
90 | 62 | }
|
91 | 63 |
|
92 | 64 | /// Creates a binding that ignores writes to its wrapped value when equivalent to the new value.
|
|
139 | 111 | )
|
140 | 112 | }
|
141 | 113 | }
|
| 114 | + |
| 115 | + extension Optional { |
| 116 | + fileprivate var _isPresent: Bool { |
| 117 | + get { self != nil } |
| 118 | + set { |
| 119 | + guard !newValue else { return } |
| 120 | + self = nil |
| 121 | + } |
| 122 | + } |
| 123 | + |
| 124 | + fileprivate subscript(default defaultSubscript: DefaultSubscript<Wrapped>) -> Wrapped { |
| 125 | + get { |
| 126 | + defaultSubscript.value = self ?? defaultSubscript.value |
| 127 | + return defaultSubscript.value |
| 128 | + } |
| 129 | + set { |
| 130 | + defaultSubscript.value = newValue |
| 131 | + if self != nil { self = newValue } |
| 132 | + } |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + private final class DefaultSubscript<Value>: Hashable { |
| 137 | + var value: Value |
| 138 | + init(_ value: Value) { |
| 139 | + self.value = value |
| 140 | + } |
| 141 | + static func == (lhs: DefaultSubscript, rhs: DefaultSubscript) -> Bool { |
| 142 | + lhs === rhs |
| 143 | + } |
| 144 | + func hash(into hasher: inout Hasher) { |
| 145 | + hasher.combine(ObjectIdentifier(self)) |
| 146 | + } |
| 147 | + } |
| 148 | + |
| 149 | + extension CasePathable { |
| 150 | + fileprivate subscript<Member>( |
| 151 | + keyPath: KeyPath<Self.AllCasePaths, AnyCasePath<Self, Member>> |
| 152 | + ) -> Member? { |
| 153 | + get { Self.allCasePaths[keyPath: keyPath].extract(from: self) } |
| 154 | + set { |
| 155 | + guard let newValue else { return } |
| 156 | + self = Self.allCasePaths[keyPath: keyPath].embed(newValue) |
| 157 | + } |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + extension Optional where Wrapped: CasePathable { |
| 162 | + fileprivate subscript<Member>( |
| 163 | + keyPath: KeyPath<Wrapped.AllCasePaths, AnyCasePath<Wrapped, Member>> |
| 164 | + ) -> Member? { |
| 165 | + get { |
| 166 | + guard let wrapped = self else { return nil } |
| 167 | + return Wrapped.allCasePaths[keyPath: keyPath].extract(from: wrapped) |
| 168 | + } |
| 169 | + set { |
| 170 | + guard let newValue else { |
| 171 | + self = nil |
| 172 | + return |
| 173 | + } |
| 174 | + self = Wrapped.allCasePaths[keyPath: keyPath].embed(newValue) |
| 175 | + } |
| 176 | + } |
| 177 | + } |
142 | 178 | #endif // canImport(SwiftUI)
|
0 commit comments