diff --git a/Sources/Verge/Library/InoutRef.swift b/Sources/Verge/Library/InoutRef.swift index c0ae4c815c..7163e1117b 100644 --- a/Sources/Verge/Library/InoutRef.swift +++ b/Sources/Verge/Library/InoutRef.swift @@ -30,7 +30,7 @@ import Foundation - Warning: Do not retain this object anywhere. */ @dynamicMemberLookup -public final class InoutRef { +public struct InoutRef: ~Copyable { // MARK: - Nested types @@ -99,7 +99,7 @@ public final class InoutRef { private(set) var nonatomic_hasModified = false - private lazy var nonatomic_modifiedKeyPaths: Set> = .init() + private var nonatomic_modifiedKeyPaths: Set> = .init() private var nonatomic_wasModifiedIndeterminate = false @@ -161,11 +161,11 @@ public final class InoutRef { } } - func append(trace: MutationTrace) { + mutating func append(trace: MutationTrace) { traces.append(trace) } - func append(traces otherTraces: [MutationTrace]) { + mutating func append(traces otherTraces: [MutationTrace]) { traces.append(contentsOf: otherTraces) } @@ -234,20 +234,20 @@ public final class InoutRef { } @inline(__always) - private func maskAsModified(on keyPath: KeyPath) { + private mutating func maskAsModified(on keyPath: KeyPath) { nonatomic_modifiedKeyPaths.insert(keyPath) nonatomic_hasModified = true } @inline(__always) - private func maskAsModified(on keyPath: KeyPath) { + private mutating func maskAsModified(on keyPath: KeyPath) { nonatomic_modifiedKeyPaths.insert(keyPath) nonatomic_hasModified = true } /// Marks as modified /// `modification` property becomes to `.indeterminate`. - public func markAsModified() { + public mutating func markAsModified() { nonatomic_hasModified = true nonatomic_wasModifiedIndeterminate = true } @@ -258,7 +258,7 @@ public final class InoutRef { We can't overload `=` operator. https://docs.swift.org/swift-book/LanguageGuide/AdvancedOperators.html */ - public func replace(with newValue: Wrapped) { + public mutating func replace(with newValue: Wrapped) { markAsModified() pointer.pointee = newValue } @@ -268,7 +268,7 @@ public final class InoutRef { /// Attention: Using this method makes modifition indeterminate. @available(*, renamed: "modifyDirectly") @discardableResult - public func modify(_ perform: (inout Wrapped) throws -> Return) rethrows -> Return { + public mutating func modify(_ perform: (inout Wrapped) throws -> Return) rethrows -> Return { return try modifyDirectly(perform) } @@ -276,7 +276,7 @@ public final class InoutRef { /// /// Attention: Using this method makes modifition indeterminate. @discardableResult - public func modifyDirectly(_ perform: (inout Wrapped) throws -> Return) rethrows -> Return { + public mutating func modifyDirectly(_ perform: (inout Wrapped) throws -> Return) rethrows -> Return { markAsModified() return try perform(&pointer.pointee) } @@ -307,15 +307,15 @@ public final class InoutRef { - SeeAlso: InoutRef.Modification */ - public func withType(_ perform: (Wrapped.Type, InoutRef) throws -> Return) rethrows -> Return { - try perform(Wrapped.self, self) + public mutating func withType(_ perform: (Wrapped.Type, inout InoutRef) throws -> Return) rethrows -> Return { + try perform(Wrapped.self, &self) } /** Returns a tantative InoutRef that projects the value specified by KeyPath. That InoutRef must be used only in the given perform closure. */ - public func map(keyPath: WritableKeyPath, perform: (inout InoutRef) throws -> Result) rethrows -> Result { + public mutating func map(keyPath: WritableKeyPath, perform: (inout InoutRef) throws -> Result) rethrows -> Result { try withUnsafeMutablePointer(to: &pointer.pointee[keyPath: keyPath]) { (pointer) in var ref = InoutRef.init(pointer) defer { @@ -336,15 +336,14 @@ public final class InoutRef { Returns a tantative InoutRef that projects the value specified by KeyPath. That InoutRef must be used only in the given perform closure. */ - public func map(keyPath: WritableKeyPath, perform: (inout InoutRef?) throws -> Result) rethrows -> Result { + public mutating func map(keyPath: WritableKeyPath, perform: (inout InoutRef) throws -> Result) rethrows -> Result? { guard pointer.pointee[keyPath: keyPath] != nil else { - var _nil: InoutRef! = .none - return try perform(&_nil) + return nil } return try withUnsafeMutablePointer(to: &pointer.pointee[keyPath: keyPath]!) { (pointer) in - var ref: InoutRef! = InoutRef.init(pointer) + var ref: InoutRef = InoutRef.init(pointer) defer { self.nonatomic_hasModified = ref.nonatomic_hasModified self.nonatomic_wasModifiedIndeterminate = ref.nonatomic_wasModifiedIndeterminate diff --git a/Sources/Verge/Store/Store.swift b/Sources/Verge/Store/Store.swift index 7141d85f15..399cce5317 100644 --- a/Sources/Verge/Store/Store.swift +++ b/Sources/Verge/Store/Store.swift @@ -175,9 +175,12 @@ open class Store: EventEmitter<_StoreEvent.init(&_initialState) - State.reduce(modifying: &inoutRef, current: .init(old: nil, new: initialState)) - let reduced = inoutRef.wrapped + + let reduced = withUnsafeMutablePointer(to: &_initialState) { pointer in + var inoutRef = InoutRef.init(pointer) + State.reduce(modifying: &inoutRef, current: .init(old: nil, new: initialState)) + return inoutRef.wrapped + } self.nonatomicValue = .init(old: nil, new: reduced) self._lock = storeOperation diff --git a/Tests/VergeTests/InoutRefTests.swift b/Tests/VergeTests/InoutRefTests.swift index 000c8642a0..c726ba3695 100644 --- a/Tests/VergeTests/InoutRefTests.swift +++ b/Tests/VergeTests/InoutRefTests.swift @@ -86,7 +86,7 @@ final class InoutTests: XCTestCase { withUnsafeMutablePointer(to: &state) { pointer in - let ref1 = InoutRef(pointer) + var ref1 = InoutRef(pointer) let ref2 = InoutRef(pointer) XCTAssertEqual(ref1.count, ref2.count) @@ -142,7 +142,7 @@ final class InoutTests: XCTestCase { }) withUnsafeMutablePointer(to: &value) { (pointer) -> Void in - let proxy = InoutRef.init(pointer) + var proxy = InoutRef.init(pointer) proxy.wrappedValue = 1 @@ -178,7 +178,7 @@ final class InoutTests: XCTestCase { var value = DemoState() let modification = withUnsafeMutablePointer(to: &value) { (pointer) -> InoutRef.Modification? in - let proxy = InoutRef.init(pointer) + var proxy = InoutRef.init(pointer) proxy.count += 1 XCTAssert(proxy.hasModified(\.self)) @@ -203,7 +203,7 @@ final class InoutTests: XCTestCase { var value = DemoState() let modification = withUnsafeMutablePointer(to: &value) { (pointer) -> InoutRef.Modification? in - let proxy = InoutRef.init(pointer) + var proxy = InoutRef.init(pointer) proxy.count += 1 proxy.map(keyPath: \.inner) { (inner) in inner.name = UUID().uuidString @@ -228,7 +228,7 @@ final class InoutTests: XCTestCase { var value = DemoState() let modification = withUnsafeMutablePointer(to: &value) { (pointer) -> InoutRef.Modification? in - let proxy = InoutRef.init(pointer) + var proxy = InoutRef.init(pointer) proxy.modify { $0.count += 1 } @@ -251,7 +251,7 @@ final class InoutTests: XCTestCase { var value = DemoState() let modification = withUnsafeMutablePointer(to: &value) { (pointer) -> InoutRef.Modification? in - let proxy = InoutRef.init(pointer) + var proxy = InoutRef.init(pointer) proxy.modify { $0.count += 1 } @@ -266,7 +266,7 @@ final class InoutTests: XCTestCase { var value = DemoState() let modification = withUnsafeMutablePointer(to: &value) { (pointer) -> InoutRef.Modification? in - let proxy = InoutRef.init(pointer) + var proxy = InoutRef.init(pointer) proxy.wrapped.updateFromItself() return proxy.modification } diff --git a/Tests/VergeTests/VergeStoreTests.swift b/Tests/VergeTests/VergeStoreTests.swift index 378a269721..0bb96f119a 100644 --- a/Tests/VergeTests/VergeStoreTests.swift +++ b/Tests/VergeTests/VergeStoreTests.swift @@ -121,17 +121,16 @@ final class VergeStoreTests: XCTestCase { let _: Changes = _detached.state - _detached.commit { state in - let _: InoutRef = state - + _detached.commit { (state: inout InoutRef) in + } let optionalNestedTarget = detached(from: \.optionalNested) let _: Changes = optionalNestedTarget.state - optionalNestedTarget.commit { state in - let _: InoutRef = state + optionalNestedTarget.commit { (state: inout InoutRef) in + } } @@ -154,16 +153,16 @@ final class VergeStoreTests: XCTestCase { let _: Changes> = state - commit { state in - let _: InoutRef> = state + commit { (state: inout InoutRef>) in + } let treeB = detached(from: \.$treeB) let _: Changes> = treeB.state - treeB.commit { state in - let _: InoutRef> = state + treeB.commit { (state: inout InoutRef>) in + } }