Skip to content

Commit 1141a53

Browse files
committed
throwing save
1 parent 1f91ee3 commit 1141a53

File tree

7 files changed

+112
-51
lines changed

7 files changed

+112
-51
lines changed

Sources/Sharing/Internal/Reference.swift

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -350,11 +350,14 @@ extension _PersistentReference: MutableReference, Equatable where Key: SharedKey
350350
try withMutation(keyPath: \.value) {
351351
saveError = nil
352352
defer {
353-
do {
354-
try key.save(value, immediately: false)
355-
loadError = nil
356-
} catch {
357-
saveError = error
353+
key.save(value, immediately: false) { [weak self] result in
354+
guard let self else { return }
355+
switch result {
356+
case .success:
357+
loadError = nil
358+
case let .failure(error):
359+
saveError = error
360+
}
358361
}
359362
}
360363
return try lock.withLock {
@@ -363,10 +366,10 @@ extension _PersistentReference: MutableReference, Equatable where Key: SharedKey
363366
}
364367
}
365368

366-
func save() throws {
369+
func save() async throws {
367370
saveError = nil
368371
do {
369-
try key.save(lock.withLock { value }, immediately: true)
372+
try await key.save(lock.withLock { value }, immediately: true)
370373
} catch {
371374
saveError = error
372375
throw error
@@ -445,8 +448,8 @@ extension _ManagedReference: MutableReference, Equatable where Key: SharedKey {
445448
try base.withLock(body)
446449
}
447450

448-
func save() throws {
449-
try base.save()
451+
func save() async throws {
452+
try await base.save()
450453
}
451454

452455
static func == (lhs: _ManagedReference, rhs: _ManagedReference) -> Bool {

Sources/Sharing/SharedKey.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,21 @@ public protocol SharedKey<Value>: SharedReaderKey {
1818
/// by default to delay writing to an external source in some way, for example throttling or
1919
/// debouncing, if `immediately` is `false`. If `immediately` is `true` it should bypass these
2020
/// delays.
21-
func save(_ value: Value, immediately: Bool) throws
21+
func save(
22+
_ value: Value,
23+
immediately: Bool,
24+
didComplete callback: @escaping @Sendable (Result<Void, any Error>) -> Void
25+
)
26+
}
27+
28+
extension SharedKey {
29+
public func save(_ value: Value, immediately: Bool = false) async throws {
30+
try await withUnsafeThrowingContinuation { continuation in
31+
save(value, immediately: immediately) { result in
32+
continuation.resume(with: result)
33+
}
34+
}
35+
}
2236
}
2337

2438
extension Shared {

Sources/Sharing/SharedKeys/AppStorageKey.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -485,8 +485,12 @@
485485
}
486486
}
487487

488-
public func save(_ value: Value, immediately: Bool) {
489-
lookup.saveValue(value, to: store.wrappedValue, at: key)
488+
public func save(
489+
_ value: Value,
490+
immediately: Bool,
491+
didComplete callback: @escaping (Result<Void, any Error>) -> Void
492+
) {
493+
callback(.success(lookup.saveValue(value, to: store.wrappedValue, at: key)))
490494
}
491495

492496
private final class Observer: NSObject, Sendable {

Sources/Sharing/SharedKeys/DefaultKey.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,12 @@ public struct _SharedKeyDefault<Base: SharedReaderKey>: SharedReaderKey {
6161
}
6262

6363
extension _SharedKeyDefault: SharedKey where Base: SharedKey {
64-
public func save(_ value: Value, immediately: Bool) throws {
65-
try base.save(value, immediately: immediately)
64+
public func save(
65+
_ value: Base.Value,
66+
immediately: Bool,
67+
didComplete callback: @escaping @Sendable (Result<Void, any Error>) -> Void
68+
) {
69+
base.save(value, immediately: immediately, didComplete: callback)
6670
}
6771
}
6872

Sources/Sharing/SharedKeys/FileStorageKey.swift

Lines changed: 55 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,19 @@
9999

100100
public func load(
101101
initialValue: Value?,
102-
didReceive callback: @escaping (Result<Value?, any Error>) -> Void
102+
didReceive callback: @escaping @Sendable (Result<Value?, any Error>) -> Void
103103
) {
104104
do {
105105
if let initialValue, !storage.fileExists(url) {
106106
try storage.createDirectory(url.deletingLastPathComponent(), true)
107-
try save(initialValue, immediately: true)
108-
callback(.success(nil))
107+
save(initialValue, immediately: true) { result in
108+
switch result {
109+
case let .failure(error):
110+
callback(.failure(error))
111+
case .success:
112+
callback(.success(nil))
113+
}
114+
}
109115
return
110116
}
111117
try callback(.success(decode(storage.load(url))))
@@ -117,44 +123,61 @@
117123
private func save(data: Data, url: URL, modificationDates: inout [Date]) throws {
118124
try self.storage.save(data, url)
119125
if let modificationDate = try storage.attributesOfItemAtPath(url.path)[.modificationDate]
120-
as? Date
126+
as? Date
121127
{
122128
modificationDates.append(modificationDate)
123129
}
124130
}
125131

126-
public func save(_ value: Value, immediately: Bool) throws {
127-
try state.withValue { state in
128-
let data = try self.encode(value)
129-
if immediately {
130-
state.value = nil
131-
state.workItem?.cancel()
132-
state.workItem = nil
133-
try self.storage.save(data, url)
134-
return
135-
}
136-
if state.workItem == nil {
137-
try save(data: data, url: url, modificationDates: &state.modificationDates)
138-
139-
let workItem = DispatchWorkItem { [weak self] in
140-
guard let self else { return }
141-
self.state.withValue { state in
142-
defer {
143-
state.value = nil
144-
state.workItem = nil
132+
public func save(
133+
_ value: Value,
134+
immediately: Bool,
135+
didComplete callback: @escaping @Sendable (Result<Void, any Error>) -> Void
136+
) {
137+
do {
138+
try state.withValue { state in
139+
let data = try self.encode(value)
140+
if immediately {
141+
state.value = nil
142+
state.workItem?.cancel()
143+
state.workItem = nil
144+
try self.storage.save(data, url)
145+
callback(.success(()))
146+
return
147+
}
148+
if state.workItem == nil {
149+
try save(data: data, url: url, modificationDates: &state.modificationDates)
150+
callback(.success(()))
151+
let workItem = DispatchWorkItem { [weak self] in
152+
guard let self else { return }
153+
self.state.withValue { state in
154+
defer {
155+
state.value = nil
156+
state.workItem = nil
157+
}
158+
guard
159+
let value = state.value,
160+
let data = try? self.encode(value)
161+
else { return }
162+
callback(
163+
Result {
164+
try self.save(
165+
data: data,
166+
url: self.url,
167+
modificationDates: &state.modificationDates
168+
)
169+
}
170+
)
145171
}
146-
guard
147-
let value = state.value,
148-
let data = try? self.encode(value)
149-
else { return }
150-
try? self.save(data: data, url: self.url, modificationDates: &state.modificationDates)
151172
}
173+
state.workItem = workItem
174+
storage.asyncAfter(.seconds(1), workItem)
175+
} else {
176+
state.value = value
152177
}
153-
state.workItem = workItem
154-
storage.asyncAfter(.seconds(1), workItem)
155-
} else {
156-
state.value = value
157178
}
179+
} catch {
180+
callback(.failure(error))
158181
}
159182
}
160183

Sources/Sharing/SharedKeys/InMemoryKey.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,13 @@ public struct InMemoryKey<Value: Sendable>: SharedKey {
5252
) -> SharedSubscription {
5353
SharedSubscription {}
5454
}
55-
public func save(_ value: Value, immediately: Bool) {
55+
public func save(
56+
_ value: Value,
57+
immediately: Bool,
58+
didComplete callback: @escaping (Result<Void, any Error>) -> Void
59+
) {
5660
store.values[key] = value
61+
callback(.success(()))
5762
}
5863
}
5964

Tests/SharingTests/SharedTests.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,8 +90,12 @@ import Testing
9090
) -> SharedSubscription {
9191
SharedSubscription {}
9292
}
93-
func save(_ value: Int, immediately: Bool) throws {
94-
if value < 0 { throw SaveError() }
93+
func save(
94+
_ value: Int,
95+
immediately: Bool,
96+
didComplete callback: @escaping (Result<Void, any Error>) -> Void
97+
) {
98+
callback(value < 0 ? .failure(SaveError()) : .success(()))
9599
}
96100
struct SaveError: Error {}
97101
}
@@ -125,8 +129,12 @@ import Testing
125129
self.callback = callback
126130
return SharedSubscription {}
127131
}
128-
func save(_ value: Int, immediately: Bool) throws {
129-
if value < 0 { throw SaveError() }
132+
func save(
133+
_ value: Int,
134+
immediately: Bool,
135+
didComplete callback: @escaping (Result<Void, any Error>) -> Void
136+
) {
137+
callback(value < 0 ? .failure(SaveError()) : .success(()))
130138
}
131139
struct LoadError: Error {}
132140
struct SaveError: Error {}

0 commit comments

Comments
 (0)