mirror of
https://github.com/RevenueCat/purchases-ios
synced 2026-11-11 22:55:55 +05:45
* Pull files from staging branch to introduce a file repository and intelligent task sharing * removed typed throws and fix some docs * Make tests satisfy predictive swift 6 failures * @_spi(Internal) public * Stop using the shared instance in an instance method * Pull cache directory logic out of file repository * update cache naming conventions * @fire-at-will feedback -> use url instead of path * Use strings file pattern * remove priority from repository * Remove RC Internal access from keyed deferred value store * Remove spi internal from cache and network service * makeSUT -> makeSystemUnderTest * remove public scope in extensions * rename function for clarity
75 lines
2.2 KiB
Swift
75 lines
2.2 KiB
Swift
//
|
|
// Copyright RevenueCat Inc. All Rights Reserved.
|
|
//
|
|
// Licensed under the MIT License (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://opensource.org/licenses/MIT
|
|
//
|
|
// KeyedDeferredValueStore.swift
|
|
//
|
|
// Created by Jacob Zivan Rakidzich on 8/12/25.
|
|
|
|
import Foundation
|
|
|
|
/// Some Task in which the value is Sendable and it can result in an error
|
|
typealias AnyTask<T: Sendable> = Task<T, Error>
|
|
|
|
/// Holds onto ``AnyTask`` objects by key, autoclearing on failure
|
|
actor KeyedDeferredValueStore<H: Hashable, T: Sendable> {
|
|
var deferred: [H: AnyTask<T>] = [:]
|
|
|
|
/// Sets the task in the cache if one is not found
|
|
/// - Parameters:
|
|
/// - task: The function that should execute if one is not found
|
|
/// - key: The key to look up the result by
|
|
/// - Returns: The stored task
|
|
func getOrPut(
|
|
_ task: @escaping @Sendable @autoclosure () -> AnyTask<T>,
|
|
forKey key: H
|
|
) -> AnyTask<T> {
|
|
guard let result = self.deferred[key] else {
|
|
let wrapped: AnyTask<T> = self.forgettingFailure(task, forKey: key)
|
|
self.deferred[key] = wrapped
|
|
return wrapped
|
|
}
|
|
return result
|
|
}
|
|
|
|
/// Replaces a task in the store
|
|
/// - Parameter task: The new function to store
|
|
/// - Parameter key: The key to look up the result by
|
|
/// - Returns: The stored task
|
|
func replaceValue(
|
|
_ task: @escaping @Sendable @autoclosure () -> AnyTask<T>,
|
|
forKey key: H
|
|
) -> AnyTask<T> {
|
|
let result = self.forgettingFailure(task, forKey: key)
|
|
self.deferred[key] = result
|
|
return result
|
|
}
|
|
|
|
/// Removes all cached tasks
|
|
func clear() {
|
|
self.deferred = [:]
|
|
}
|
|
|
|
private func forgettingFailure(
|
|
_ task: @escaping @Sendable () -> AnyTask<T>,
|
|
forKey key: H
|
|
) -> AnyTask<T> {
|
|
Task {
|
|
do {
|
|
return try await task().value
|
|
} catch {
|
|
self.deferred.removeValue(forKey: key)
|
|
throw error
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Create a KeyedDeferredValueStore
|
|
init() {}
|
|
}
|