diff --git a/Sources/Sharing/SharedKey.swift b/Sources/Sharing/SharedKey.swift index e64899c..3581d9a 100644 --- a/Sources/Sharing/SharedKey.swift +++ b/Sources/Sharing/SharedKey.swift @@ -82,6 +82,12 @@ extension Shared { self.init(wrappedValue: wrappedValue(), key.base) } + /// Replaces a shared reference's key with a shared key that provides a default value and + /// attempts to load its value. + public func load>(_ key: K.Default) async throws { + try await load(key.base) + } + /// Replaces a shared reference's key and attempts to load its value. /// /// - Parameter key: A shared key associated with the shared reference. It is responsible for @@ -100,6 +106,12 @@ extension Shared { try await load() } + /// Creates a shared reference from a shared key that provides a default value by loading it + /// from its external source. + public init>(require key: K.Default) async throws { + try await self.init(require: key.base) + } + /// Creates a shared reference to a value using a shared key by loading it from its external /// source. /// diff --git a/Sources/Sharing/SharedReaderKey.swift b/Sources/Sharing/SharedReaderKey.swift index 6e8aba2..6b298b1 100644 --- a/Sources/Sharing/SharedReaderKey.swift +++ b/Sources/Sharing/SharedReaderKey.swift @@ -149,6 +149,12 @@ extension SharedReader { self.init(wrappedValue: wrappedValue(), key.base) } + /// Replaces a shared reference's key with a shared key that provides a default value and + /// attempts to load its value. + public func load>(_ key: K.Default) async throws { + try await load(key.base) + } + /// Replaces a shared reference's key and attempts to load its value. /// /// - Parameter key: A shared key associated with the shared reference. It is responsible for @@ -173,6 +179,12 @@ extension SharedReader { try await load(key) } + /// Creates a shared reference from a shared key that provides a default value by loading it from + /// its external source. + public init>(require key: K.Default) async throws { + try await self.init(require: key.base) + } + /// Creates a shared reference to a read-only value using a shared key by loading it from its /// external source. /// diff --git a/Tests/SharingTests/DefaultTests.swift b/Tests/SharingTests/DefaultTests.swift index bf2a707..990f216 100644 --- a/Tests/SharingTests/DefaultTests.swift +++ b/Tests/SharingTests/DefaultTests.swift @@ -1,3 +1,4 @@ +import ConcurrencyExtras import Sharing import Testing @@ -149,6 +150,85 @@ import Testing #expect(count == 3) #expect(countReader == 3) } + + @Test func loadDefaultKeyUsesBaseReference() async throws { + let subscriptionCount = LockIsolated(0) + let key = SubscriptionCountingKey( + id: "loadDefaultKeyUsesBaseReference", + subscriptionCount: subscriptionCount + ) + let defaultKey = SubscriptionCountingKey.Default[key, default: 0] + + @SharedReader(value: 0) var value + try await $value.load(defaultKey) + @SharedReader(defaultKey) var otherValue + + #expect(subscriptionCount.value == 1) + } + + @Test func requireDefaultKeyUsesBaseReference() async throws { + let subscriptionCount = LockIsolated(0) + let key = SubscriptionCountingKey( + id: "requireDefaultKeyUsesBaseReference", + subscriptionCount: subscriptionCount + ) + let defaultKey = SubscriptionCountingKey.Default[key, default: 0] + + let value = try await SharedReader(require: defaultKey) + @SharedReader(defaultKey) var otherValue + + #expect(subscriptionCount.value == 1) + } + + @Test func sharedLoadDefaultKeyUsesBaseReference() async throws { + let subscriptionCount = LockIsolated(0) + let key = SubscriptionCountingKey( + id: "sharedLoadDefaultKeyUsesBaseReference", + subscriptionCount: subscriptionCount + ) + let defaultKey = SubscriptionCountingKey.Default[key, default: 0] + + @Shared(value: 0) var value + try await $value.load(defaultKey) + @Shared(defaultKey) var otherValue + + #expect(subscriptionCount.value == 1) + } + + @Test func sharedRequireDefaultKeyUsesBaseReference() async throws { + let subscriptionCount = LockIsolated(0) + let key = SubscriptionCountingKey( + id: "sharedRequireDefaultKeyUsesBaseReference", + subscriptionCount: subscriptionCount + ) + let defaultKey = SubscriptionCountingKey.Default[key, default: 0] + + let value = try await Shared(require: defaultKey) + @Shared(defaultKey) var otherValue + + #expect(subscriptionCount.value == 1) + } + } +} + +private struct SubscriptionCountingKey: SharedKey { + let id: String + let subscriptionCount: LockIsolated + + func load(context: LoadContext, continuation: LoadContinuation) { + continuation.resume(returning: 0) + } + + func subscribe( + context: LoadContext, + subscriber: SharedSubscriber + ) -> SharedSubscription { + subscriptionCount.withValue { $0 += 1 } + return SharedSubscription {} + } + + func save(_ value: Int, context: SaveContext, continuation: SaveContinuation) { + continuation.resume() } }