Skip to content

Commit

Permalink
- add asyncMapValues and validate: two new async operators
Browse files Browse the repository at this point in the history
- deprecate `update`, deprecated non-async `set` without a completion handler (for swift 5.5)
  • Loading branch information
dreymonde committed May 1, 2022
1 parent 226269e commit 36290c8
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 5 deletions.
108 changes: 108 additions & 0 deletions Sources/Shallows/Async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,112 @@ extension WritableStorageProtocol where Key == Void {
})
}
}

public struct ValueValidationError: Error {
public init() { }
}

@available(iOS 13.0.0, *)
@available(macOS 10.15.0, *)
@available(watchOS 6.0, *)
@available(tvOS 13.0.0, *)
extension ReadOnlyStorageProtocol {
public func asyncMapValues<OtherValue>(
to type: OtherValue.Type = OtherValue.self,
_ transform: @escaping (Value) async throws -> OtherValue
) -> ReadOnlyStorage<Key, OtherValue> {
return ReadOnlyStorage<Key, OtherValue>(storageName: storageName, retrieve: { (key, completion) in
self.retrieve(forKey: key, completion: { (result) in
switch result {
case .success(let value):
Task {
do {
let newValue = try await transform(value)
completion(.success(newValue))
} catch {
completion(.failure(error))
}
}
case .failure(let error):
completion(.failure(error))
}
})
})
}

public func validate(_ isValid: @escaping (Value) async throws -> Bool) -> ReadOnlyStorage<Key, Value> {
return asyncMapValues(to: Value.self) { value in
if try await isValid(value) {
return value
} else {
throw ValueValidationError()
}
}
}
}

@available(iOS 13.0.0, *)
@available(macOS 10.15.0, *)
@available(watchOS 6.0, *)
@available(tvOS 13.0.0, *)
extension WriteOnlyStorageProtocol {
public func asyncMapValues<OtherValue>(
to type: OtherValue.Type = OtherValue.self,
_ transform: @escaping (OtherValue) async throws -> Value
) -> WriteOnlyStorage<Key, OtherValue> {
return WriteOnlyStorage<Key, OtherValue>(storageName: storageName, set: { (value, key, completion) in
Task {
do {
let newValue = try await transform(value)
self.set(newValue, forKey: key, completion: completion)
} catch {
completion(.failure(error))
}
}
})
}

public func validate(_ isValid: @escaping (Value) async throws -> Bool) -> WriteOnlyStorage<Key, Value> {
return asyncMapValues(to: Value.self) { value in
if try await isValid(value) {
return value
} else {
throw ValueValidationError()
}
}
}
}

@available(iOS 13.0.0, *)
@available(macOS 10.15.0, *)
@available(watchOS 6.0, *)
@available(tvOS 13.0.0, *)
extension StorageProtocol {
public func asyncMapValues<OtherValue>(to type: OtherValue.Type = OtherValue.self,
transformIn: @escaping (Value) async throws -> OtherValue,
transformOut: @escaping (OtherValue) async throws -> Value) -> Storage<Key, OtherValue> {
return Storage(read: asReadOnlyStorage().asyncMapValues(transformIn),
write: asWriteOnlyStorage().asyncMapValues(transformOut))
}

public func validate(_ isValid: @escaping (Value) async throws -> Bool) -> Storage<Key, Value> {
return asyncMapValues(
to: Value.self,
transformIn: { value in
if try await isValid(value) {
return value
} else {
throw ValueValidationError()
}
},
transformOut: { value in
if try await isValid(value) {
return value
} else {
throw ValueValidationError()
}
}
)
}
}
#endif
21 changes: 16 additions & 5 deletions Sources/Shallows/Storage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,14 @@ public struct Storage<Key, Value> : StorageProtocol {
_retrieve.retrieve(forKey: key, completion: completion)
}

public func set(_ value: Value, forKey key: Key, completion: @escaping (ShallowsResult<Void>) -> () = { _ in }) {
public func set(_ value: Value, forKey key: Key, completion: @escaping (ShallowsResult<Void>) -> ()) {
_set.set(value, forKey: key, completion: completion)
}

@available(swift, deprecated: 5.5, message: "use async version or provide completion handler explicitly")
public func set(_ value: Value, forKey key: Key) {
_set.set(value, forKey: key, completion: { _ in })
}

public func asReadOnlyStorage() -> ReadOnlyStorage<Key, Value> {
return _retrieve
Expand Down Expand Up @@ -89,7 +94,8 @@ extension StorageProtocol {
}
return Storage(self)
}


@available(swift, deprecated: 5.5, message: "`update` is deprecated because it was creating potentially wrong assumptions regarding the serial nature of this function. `update` cannot guarantee that no concurrent calls to `retrieve` or `set` from other places will be made during the update")
public func update(forKey key: Key,
_ modify: @escaping (inout Value) -> (),
completion: @escaping (ShallowsResult<Value>) -> () = { _ in }) {
Expand Down Expand Up @@ -173,14 +179,19 @@ extension ReadableStorageProtocol where Key == Void {

extension WritableStorageProtocol where Key == Void {

public func set(_ value: Value, completion: @escaping (ShallowsResult<Void>) -> () = { _ in }) {
public func set(_ value: Value, completion: @escaping (ShallowsResult<Void>) -> ()) {
set(value, forKey: (), completion: completion)
}


@available(swift, deprecated: 5.5, message: "use async version or provide completion handler explicitly")
public func set(_ value: Value) {
set(value, completion: { _ in })
}
}

extension StorageProtocol where Key == Void {


@available(swift, deprecated: 5.5, message: "`update` is deprecated because it was creating potentially wrong assumptions regarding the serial nature of this function. `update` cannot guarantee that no concurrent calls to `retrieve` or `set` from other places will be made during the update")
public func update(_ modify: @escaping (inout Value) -> (), completion: @escaping (ShallowsResult<Value>) -> () = {_ in }) {
self.update(forKey: (), modify, completion: completion)
}
Expand Down

0 comments on commit 36290c8

Please sign in to comment.