11import Foundation
22
33/// Save objects to file on disk
4- final public class DiskStorage < T > {
4+ final public class DiskStorage < Key : Hashable , Value > {
55 enum Error : Swift . Error {
66 case fileEnumeratorFailed
77 }
@@ -15,10 +15,11 @@ final public class DiskStorage<T> {
1515 /// The closure to be called when single file has been removed
1616 var onRemove : ( ( String ) -> Void ) ?
1717
18- private let transformer : Transformer < T >
18+ private let transformer : Transformer < Value >
19+ private let hasher = Hasher . constantAccrossExecutions ( )
1920
2021 // MARK: - Initialization
21- public convenience init ( config: DiskConfig , fileManager: FileManager = FileManager . default, transformer: Transformer < T > ) throws {
22+ public convenience init ( config: DiskConfig , fileManager: FileManager = FileManager . default, transformer: Transformer < Value > ) throws {
2223 let url : URL
2324 if let directory = config. directory {
2425 url = directory
@@ -48,7 +49,7 @@ final public class DiskStorage<T> {
4849 #endif
4950 }
5051
51- public required init ( config: DiskConfig , fileManager: FileManager = FileManager . default, path: String , transformer: Transformer < T > ) {
52+ public required init ( config: DiskConfig , fileManager: FileManager = FileManager . default, path: String , transformer: Transformer < Value > ) {
5253 self . config = config
5354 self . fileManager = fileManager
5455 self . path = path
@@ -57,7 +58,7 @@ final public class DiskStorage<T> {
5758}
5859
5960extension DiskStorage : StorageAware {
60- public func entry( forKey key: String ) throws -> Entry < T > {
61+ public func entry( forKey key: Key ) throws -> Entry < Value > {
6162 let filePath = makeFilePath ( for: key)
6263 let data = try Data ( contentsOf: URL ( fileURLWithPath: filePath) )
6364 let attributes = try fileManager. attributesOfItem ( atPath: filePath)
@@ -74,15 +75,15 @@ extension DiskStorage: StorageAware {
7475 )
7576 }
7677
77- public func setObject( _ object: T , forKey key: String , expiry: Expiry ? = nil ) throws {
78+ public func setObject( _ object: Value , forKey key: Key , expiry: Expiry ? = nil ) throws {
7879 let expiry = expiry ?? config. expiry
7980 let data = try transformer. toData ( object)
8081 let filePath = makeFilePath ( for: key)
8182 _ = fileManager. createFile ( atPath: filePath, contents: data, attributes: nil )
8283 try fileManager. setAttributes ( [ . modificationDate: expiry. date] , ofItemAtPath: filePath)
8384 }
8485
85- public func removeObject( forKey key: String ) throws {
86+ public func removeObject( forKey key: Key ) throws {
8687 let filePath = makeFilePath ( for: key)
8788 try fileManager. removeItem ( atPath: filePath)
8889 onRemove ? ( filePath)
@@ -160,24 +161,30 @@ extension DiskStorage {
160161 - Parameter key: Unique key to identify the object in the cache
161162 - Returns: A md5 string
162163 */
163- func makeFileName( for key: String ) -> String {
164- let fileExtension = URL ( fileURLWithPath: key) . pathExtension
165- let fileName = MD5 ( key)
166-
167- switch fileExtension. isEmpty {
168- case true :
169- return fileName
170- case false :
171- return " \( fileName) . \( fileExtension) "
164+ func makeFileName( for key: Key ) -> String {
165+ if let key = key as? String {
166+ let fileExtension = URL ( fileURLWithPath: key) . pathExtension
167+ let fileName = MD5 ( key)
168+
169+ switch fileExtension. isEmpty {
170+ case true :
171+ return fileName
172+ case false :
173+ return " \( fileName) . \( fileExtension) "
174+ }
172175 }
176+
177+ var hasher = self . hasher
178+ key. hash ( into: & hasher)
179+ return String ( hasher. finalize ( ) )
173180 }
174181
175182 /**
176183 Builds file path from the key.
177184 - Parameter key: Unique key to identify the object in the cache
178185 - Returns: A string path based on key
179186 */
180- func makeFilePath( for key: String ) -> String {
187+ func makeFilePath( for key: Key ) -> String {
181188 return " \( path) / \( makeFileName ( for: key) ) "
182189 }
183190
@@ -244,7 +251,7 @@ extension DiskStorage {
244251 Removes the object from the cache if it's expired.
245252 - Parameter key: Unique key to identify the object in the cache
246253 */
247- func removeObjectIfExpired( forKey key: String ) throws {
254+ func removeObjectIfExpired( forKey key: Key ) throws {
248255 let filePath = makeFilePath ( for: key)
249256 let attributes = try fileManager. attributesOfItem ( atPath: filePath)
250257 if let expiryDate = attributes [ . modificationDate] as? Date , expiryDate. inThePast {
@@ -255,8 +262,8 @@ extension DiskStorage {
255262}
256263
257264public extension DiskStorage {
258- func transform< U> ( transformer: Transformer < U > ) -> DiskStorage < U > {
259- let storage = DiskStorage < U > (
265+ func transform< U> ( transformer: Transformer < U > ) -> DiskStorage < Key , U > {
266+ let storage = DiskStorage < Key , U > (
260267 config: config,
261268 fileManager: fileManager,
262269 path: path,
0 commit comments