Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix race condition in FileStorageKey #3479

Merged
merged 6 commits into from
Nov 12, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -45,7 +45,6 @@ extension PersistenceReaderKey {
/// Use ``PersistenceReaderKey/fileStorage(_:decoder:encoder:)`` to create values of this type.
public final class FileStorageKey<Value: Sendable>: PersistenceKey, Sendable {
private let storage: FileStorage
private let isSetting = LockIsolated(false)
private let url: URL
private let decode: @Sendable (Data) throws -> Value
private let encode: @Sendable (Value) throws -> Data
@@ -83,7 +82,6 @@ public final class FileStorageKey<Value: Sendable>: PersistenceKey, Sendable {
public func save(_ value: Value) {
self.state.withValue { state in
if state.workItem == nil {
self.isSetting.setValue(true)
try? self.storage.save(encode(value), self.url)
let workItem = DispatchWorkItem { [weak self] in
guard let self else { return }
@@ -94,7 +92,6 @@ public final class FileStorageKey<Value: Sendable>: PersistenceKey, Sendable {
}
guard let value = state.value
else { return }
self.isSetting.setValue(true)
try? self.storage.save(self.encode(value), self.url)
}
}
@@ -125,14 +122,12 @@ public final class FileStorageKey<Value: Sendable>: PersistenceKey, Sendable {
try? self.storage.save(Data(), self.url)
}
let writeCancellable = self.storage.fileSystemSource(self.url, [.write]) {
// TODO: Improve this by fingerprinting (by adding extra bytes?) the file we write to the
// file system so that we can early out of this closure.
self.state.withValue { state in
if self.isSetting.value == true {
self.isSetting.setValue(false)
} else {
state.workItem?.cancel()
state.workItem = nil
didSet(self.load(initialValue: initialValue))
}
guard state.workItem == nil
else { return }
didSet(self.load(initialValue: initialValue))
}
}
let deleteCancellable = self.storage.fileSystemSource(self.url, [.delete, .rename]) {
@@ -265,15 +260,6 @@ public struct FileStorage: Hashable, Sendable {
let load: @Sendable (URL) throws -> Data
@_spi(Internals) public let save: @Sendable (Data, URL) throws -> Void

/// File storage that interacts directly with the file system for saving, loading and listening
/// for file changes.
///
/// This is the version of the ``Dependencies/DependencyValues/defaultFileStorage`` dependency
/// that is used by default when running your app in the simulator or on device.
public static let fileSystem = fileSystem(
queue: DispatchQueue(label: "co.pointfree.ComposableArchitecture.FileStorage")
)

/// File storage that emulates a file system without actually writing anything to disk.
///
/// This is the version of the ``Dependencies/DependencyValues/defaultFileStorage`` dependency
@@ -282,32 +268,35 @@ public struct FileStorage: Hashable, Sendable {
inMemory(fileSystem: LockIsolated([:]))
}

@_spi(Internals) public static func fileSystem(queue: DispatchQueue) -> Self {
Self(
id: AnyHashableSendable(queue),
async: { queue.async(execute: $0) },
asyncAfter: { queue.asyncAfter(deadline: .now() + $0, execute: $1) },
createDirectory: {
try FileManager.default.createDirectory(at: $0, withIntermediateDirectories: $1)
},
fileExists: { FileManager.default.fileExists(atPath: $0.path) },
fileSystemSource: {
let source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: open($0.path, O_EVTONLY),
eventMask: $1,
queue: queue
)
source.setEventHandler(handler: $2)
source.resume()
return AnyCancellable {
source.cancel()
close(source.handle)
}
},
load: { try Data(contentsOf: $0) },
save: { try $0.write(to: $1) }
)
}
/// File storage that interacts directly with the file system for saving, loading and listening
/// for file changes.
///
/// This is the version of the ``Dependencies/DependencyValues/defaultFileStorage`` dependency
/// that is used by default when running your app in the simulator or on device.
public static let fileSystem = Self(
id: AnyHashableSendable(DispatchQueue.main),
async: { DispatchQueue.main.async(execute: $0) },
asyncAfter: { DispatchQueue.main.asyncAfter(deadline: .now() + $0, execute: $1) },
createDirectory: {
try FileManager.default.createDirectory(at: $0, withIntermediateDirectories: $1)
},
fileExists: { FileManager.default.fileExists(atPath: $0.path) },
fileSystemSource: {
let source = DispatchSource.makeFileSystemObjectSource(
fileDescriptor: open($0.path, O_EVTONLY),
eventMask: $1,
queue: .main
)
source.setEventHandler(handler: $2)
source.resume()
return AnyCancellable {
source.cancel()
close(source.handle)
}
},
load: { try Data(contentsOf: $0) },
save: { try $0.write(to: $1) }
)

@_spi(Internals) public static func inMemory(
fileSystem: LockIsolated<[URL: Data]>,
75 changes: 68 additions & 7 deletions Tests/ComposableArchitectureTests/FileStorageTests.swift
Original file line number Diff line number Diff line change
@@ -163,7 +163,7 @@ final class FileStorageTests: XCTestCase {
try? FileManager.default.removeItem(at: .fileURL)

try await withDependencies {
$0.defaultFileStorage = .fileSystem(queue: .main)
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.fileStorage(.fileURL)) var users = [User]()

@@ -201,7 +201,7 @@ final class FileStorageTests: XCTestCase {
try JSONEncoder().encode([User.blob]).write(to: .fileURL)

try await withDependencies {
$0.defaultFileStorage = .fileSystem(queue: .main)
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.fileStorage(.fileURL)) var users = [User]()
_ = users
@@ -220,7 +220,7 @@ final class FileStorageTests: XCTestCase {
try JSONEncoder().encode([User.blob]).write(to: .fileURL)

try await withDependencies {
$0.defaultFileStorage = .fileSystem(queue: .main)
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.fileStorage(.fileURL)) var users = [User]()
await Task.yield()
@@ -251,7 +251,7 @@ final class FileStorageTests: XCTestCase {

try fileStorage.save(Data(), .fileURL)
scheduler.run()
expectNoDifference(users, [])
expectNoDifference(users, [.blob])
Comment on lines 252 to +254
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes made to the file on disk will be ignored if there is an enqueued state change waiting to be saved.

try expectNoDifference(fileSystem.value.users(for: .fileURL), nil)
}
}
@@ -262,7 +262,7 @@ final class FileStorageTests: XCTestCase {
try JSONEncoder().encode([User.blob]).write(to: .fileURL)

try await withDependencies {
$0.defaultFileStorage = .fileSystem(queue: .main)
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.fileStorage(.fileURL)) var users = [User]()
await Task.yield()
@@ -282,7 +282,7 @@ final class FileStorageTests: XCTestCase {
try JSONEncoder().encode([User.blob]).write(to: .fileURL)

try await withDependencies {
$0.defaultFileStorage = .fileSystem(queue: .main)
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.fileStorage(.fileURL)) var users = [User]()
await Task.yield()
@@ -306,7 +306,7 @@ final class FileStorageTests: XCTestCase {
try JSONEncoder().encode([User.blob]).write(to: .fileURL)

try await withDependencies {
$0.defaultFileStorage = .fileSystem(queue: .main)
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.fileStorage(.fileURL)) var users = [User]()
await Task.yield()
@@ -471,6 +471,56 @@ final class FileStorageTests: XCTestCase {
await fulfillment(of: [publisherExpectation], timeout: 1)
}
}

@MainActor
func testMultipleMutations() async throws {
try? FileManager.default.removeItem(
at: URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("counts.json")
)

try await withDependencies {
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.counts) var counts
for m in 1...1000 {
for n in 1...10 {
$counts.withLock {
$0[n, default: 0] += 1
}
}
expectNoDifference(
Dictionary((1...10).map { n in (n, m) }, uniquingKeysWith: { $1 }),
counts
)
try await Task.sleep(for: .seconds(0.001))
}
}
}

func testMultipleMutationsFromMultipleThreads() async throws {
try? FileManager.default.removeItem(
at: URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("counts.json")
)

await withDependencies {
$0.defaultFileStorage = .fileSystem
} operation: {
@Shared(.counts) var counts

await withTaskGroup(of: Void.self) { group in
for _ in 1...1000 {
group.addTask { [$counts] in
for _ in 1...10 {
await $counts.withLock { $0[0, default: 0] += 1 }
try? await Task.sleep(for: .seconds(0.2))
}
}
}
}

XCTAssertEqual(counts[0], 10_000)
}
}
}

extension PersistenceReaderKey
@@ -513,3 +563,14 @@ extension [URL: Data] {
return try JSONDecoder().decode([User].self, from: data)
}
}

extension PersistenceKey where Self == PersistenceKeyDefault<FileStorageKey<[Int: Int]>> {
fileprivate static var counts: Self {
Self(
.fileStorage(
URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("counts.json")
),
[:]
)
}
}

Unchanged files with check annotations Beta

///
/// See ``PersistenceReaderKey/appStorage(_:)-5jsie`` to create values of this type.
public struct AppStorageKeyPathKey<Value: Sendable>: Sendable {
private let keyPath: _SendableReferenceWritableKeyPath<UserDefaults, Value>

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (MACOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (MACOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (IOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (IOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')

Check warning on line 28 in Sources/ComposableArchitecture/SharedState/PersistenceKey/AppStorageKeyPathKey.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'AppStorageKeyPathKey' has non-sendable type '_SendableReferenceWritableKeyPath<UserDefaults, Value>' (aka 'ReferenceWritableKeyPath<UserDefaults, Value>')
private let store: UncheckedSendable<UserDefaults>
public init(_ keyPath: _SendableReferenceWritableKeyPath<UserDefaults, Value>) {
@propertyWrapper
public struct Shared<Value: Sendable>: Sendable {
private let reference: any Reference
private let keyPath: _SendableAnyKeyPath

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (MACOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (MACOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (IOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (IOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')

Check warning on line 17 in Sources/ComposableArchitecture/SharedState/Shared.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'Shared' has non-sendable type '_SendableAnyKeyPath' (aka 'AnyKeyPath')
init(reference: any Reference, keyPath: _SendableAnyKeyPath) {
self.reference = reference
///
/// Read <doc:Bindings> for more information.
public struct BindingAction<Root>: CasePathable, Equatable, Sendable {
public let keyPath: _SendablePartialKeyPath<Root>

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (MACOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (MACOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (IOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (IOS, 15.2)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')

Check warning on line 147 in Sources/ComposableArchitecture/SwiftUI/Binding.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

stored property 'keyPath' of 'Sendable'-conforming generic struct 'BindingAction' has non-sendable type '_SendablePartialKeyPath<Root>' (aka 'PartialKeyPath<Root>')
@usableFromInline
let set: @Sendable (inout Root) -> Void
}
func testCopyMutation() async {
XCTTODO(

Check warning on line 22 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 22 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 22 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 22 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, WATCHOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 22 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 22 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.
"""
Ideally this test would pass but it does not because making a copy of a child state, mutating
it, and assigning it does not change the identified array's IDs, and therefore the fast-path
}
func testReplace() async {
XCTTODO("Ideally this would pass but we cannot detect this kind of mutation currently.")

Check warning on line 66 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 66 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 66 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 66 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 66 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.
var state = ChildState(count: 42)
let countDidChange = self.expectation(description: "count.didChange")
}
func testReset() async {
XCTTODO("Ideally this would pass but we cannot detect this kind of mutation currently.")

Check warning on line 83 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, TVOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 83 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, MACOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 83 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, MAC_CATALYST, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 83 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, IOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.

Check warning on line 83 in Tests/ComposableArchitectureTests/ObservableTests.swift

GitHub Actions / xcodebuild (15) (test, VISIONOS, 15.4)

'XCTTODO' is deprecated: This is a test that currently fails but should not in the future.
var state = ChildState(count: 42)
let countDidChange = self.expectation(description: "count.didChange")