mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			127 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			127 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Swift
		
	
| // Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
 | |
| 
 | |
| import Foundation
 | |
| 
 | |
| // MARK: - CacheType
 | |
| 
 | |
| public protocol MutableCacheType {}
 | |
| public protocol ImmutableCacheType {}
 | |
| 
 | |
| // MARK: - Cache
 | |
| 
 | |
| public class Cache {}
 | |
| 
 | |
| // MARK: - CacheInfo
 | |
| 
 | |
| public enum CacheInfo {
 | |
|     public class Config<M, I>: Cache {
 | |
|         public let key: Int
 | |
|         public let createInstance: () -> M
 | |
|         public let mutableInstance: (M) -> MutableCacheType
 | |
|         public let immutableInstance: (M) -> I
 | |
|         
 | |
|         fileprivate init(
 | |
|             createInstance: @escaping () -> M,
 | |
|             mutableInstance: @escaping (M) -> MutableCacheType,
 | |
|             immutableInstance: @escaping (M) -> I
 | |
|         ) {
 | |
|             self.key = ObjectIdentifier(M.self).hashValue
 | |
|             self.createInstance = createInstance
 | |
|             self.mutableInstance = mutableInstance
 | |
|             self.immutableInstance = immutableInstance
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| public extension CacheInfo {
 | |
|     static func create<M, I>(
 | |
|         createInstance: @escaping () -> M,
 | |
|         mutableInstance: @escaping (M) -> MutableCacheType,
 | |
|         immutableInstance: @escaping (M) -> I
 | |
|     ) -> CacheInfo.Config<M, I> {
 | |
|         return CacheInfo.Config(
 | |
|             createInstance: createInstance,
 | |
|             mutableInstance: mutableInstance,
 | |
|             immutableInstance: immutableInstance
 | |
|         )
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| public protocol CacheType: MutableCacheType {
 | |
|     associatedtype ImmutableCache = ImmutableCacheType
 | |
|     associatedtype MutableCache: MutableCacheType
 | |
|     
 | |
|     init()
 | |
|     func mutableInstance() -> MutableCache
 | |
|     func immutableInstance() -> ImmutableCache
 | |
| }
 | |
| 
 | |
| public extension CacheType where MutableCache == Self {
 | |
|     func mutableInstance() -> Self { return self }
 | |
| }
 | |
| 
 | |
| public protocol CachesType {
 | |
|     subscript<M, I>(cache: CacheInfo.Config<M, I>) -> I { get }
 | |
|     
 | |
|     @discardableResult func mutate<M, I, R>(
 | |
|         cache: CacheInfo.Config<M, I>,
 | |
|         _ mutation: (inout M) -> R
 | |
|     ) -> R
 | |
|     @discardableResult func mutate<M, I, R>(
 | |
|         cache: CacheInfo.Config<M, I>,
 | |
|         _ mutation: (inout M) throws -> R
 | |
|     ) throws -> R
 | |
| }
 | |
| 
 | |
| // MARK: - Caches Logic
 | |
| 
 | |
| public extension Dependencies {
 | |
|     class Caches: CachesType {
 | |
|         /// The caches need to be accessed as singleton instances so we store them in a static variable in the `Caches` type
 | |
|         private static var cacheInstances: Atomic<[Int: MutableCacheType]> = Atomic([:])
 | |
|         
 | |
|         // MARK: - Initialization
 | |
|         
 | |
|         public init() {}
 | |
|         
 | |
|         // MARK: - Immutable Access
 | |
|         
 | |
|         public subscript<M, I>(cache: CacheInfo.Config<M, I>) -> I {
 | |
|             get { Caches.getValueSettingIfNull(cache: cache, &Caches.cacheInstances) }
 | |
|         }
 | |
|         
 | |
|         // MARK: - Mutable Access
 | |
|         
 | |
|         @discardableResult public func mutate<M, I, R>(cache: CacheInfo.Config<M, I>, _ mutation: (inout M) -> R) -> R {
 | |
|             return Caches.cacheInstances.mutate { caches in
 | |
|                 var value: M = ((caches[cache.key] as? M) ?? cache.createInstance())
 | |
|                 return mutation(&value)
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         @discardableResult public func mutate<M, I, R>(cache: CacheInfo.Config<M, I>, _ mutation: (inout M) throws -> R) throws -> R {
 | |
|             return try Caches.cacheInstances.mutate { caches in
 | |
|                 var value: M = ((caches[cache.key] as? M) ?? cache.createInstance())
 | |
|                 return try mutation(&value)
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         // MARK: - Convenience
 | |
|         
 | |
|         @discardableResult private static func getValueSettingIfNull<M, I>(
 | |
|             cache: CacheInfo.Config<M, I>,
 | |
|             _ store: inout Atomic<[Int: MutableCacheType]>
 | |
|         ) -> I {
 | |
|             guard let value: M = (store.wrappedValue[cache.key] as? M) else {
 | |
|                 let value: M = cache.createInstance()
 | |
|                 let mutableInstance: MutableCacheType = cache.mutableInstance(value)
 | |
|                 store.mutate { $0[cache.key] = mutableInstance }
 | |
|                 return cache.immutableInstance(value)
 | |
|             }
 | |
|             
 | |
|             return cache.immutableInstance(value)
 | |
|         }
 | |
|     }
 | |
| }
 |