// // EphemeralPreferenceStore.swift // // Copyright 2026 Brendan Szymanski // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program. If not, see . // // SPDX-License-Identifier: GPL-3.0-or-later // /// An ordered in-memory preference backend for tests and persistence fallback. package actor EphemeralPreferenceStore: PreferenceStoring { package nonisolated let initialSnapshot: [String: StoredPreference] private var values: [String: StoredPreference] private nonisolated let continuation: AsyncStream.Continuation /// Creates an in-memory store seeded with optional raw values. /// /// - Parameter initialSnapshot: Values available before the first write. package init(initialSnapshot: [String: StoredPreference] = [:]) { self.initialSnapshot = initialSnapshot values = initialSnapshot let (stream, continuation) = AsyncStream.makeStream(bufferingPolicy: .unbounded) self.continuation = continuation Task { [weak self] in for await write in stream { guard let self else { break } await self.apply(write) } } } deinit { continuation.finish() } /// Queues a value update or deletion without blocking the caller. package nonisolated func enqueue(_ key: String, _ value: StoredPreference?) { continuation.yield(.set(key: key, value: value)) } /// Returns after queued writes have been applied to the in-memory values. /// /// - Throws: Never; the in-memory backend has no write failure mode. package nonisolated func flush() async throws { try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in self.continuation.yield( .barrier { error in if let error { continuation.resume(throwing: error) } else { continuation.resume(returning: ()) } }) } } /// The values currently held, for assertions. package var storedValues: [String: StoredPreference] { values } private func apply(_ write: PreferenceWrite) { switch write { case .set(let key, let value): if let value { values[key] = value } else { values.removeValue(forKey: key) } case .barrier(let resume): resume(nil) } } }