1
1
import Foundation
2
2
import OSLog
3
3
4
- public final class Cache < Key: Hashable & Sendable , Value: Codable & Sendable > : Caching , @unchecked Sendable {
5
- public typealias Options = ( forMemory: MemoryCache < Key , Value > . Options , forDisk: DiskCache < Key > . Options )
4
+ public actor Cache < Key: Hashable & Sendable , Value: Codable & Sendable > : Caching {
5
+ public struct Options : Sendable {
6
+ public let forMemory : MemoryCache < Key , Value > . Options
7
+ public let forDisk : DiskCache < Key > . Options
8
+
9
+ public init ( forMemory: MemoryCache < Key , Value > . Options , forDisk: DiskCache < Key > . Options ) {
10
+ self . forMemory = forMemory
11
+ self . forDisk = forDisk
12
+ }
13
+ }
6
14
7
- public let options : Options
8
- public let logger : Logger
15
+ public nonisolated let options : Options
16
+ public nonisolated let logger : Logger
9
17
10
18
public subscript ( key: Key ) -> Value ? {
11
19
get async throws {
@@ -16,7 +24,6 @@ public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: C
16
24
private let onMemery : MemoryCache < Key , Value >
17
25
private let onDisk : DiskCache < Key >
18
26
19
- private let queueingLock = NSLock ( )
20
27
private var queueingTask : Task < Void , Never > ?
21
28
22
29
public init ( options: Options , logger: Logger = . init( . disabled) ) {
@@ -26,8 +33,8 @@ public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: C
26
33
self . logger = logger
27
34
}
28
35
29
- public func prepare( ) throws {
30
- try onDisk. prepare ( )
36
+ public func prepare( ) async throws {
37
+ try await onDisk. prepare ( )
31
38
}
32
39
33
40
public func value( for key: Key ) async throws -> Value ? {
@@ -46,64 +53,48 @@ public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: C
46
53
return try decoder. decode ( Value . self, from: data)
47
54
} ( )
48
55
49
- onMemery. store ( value, for: key)
56
+ await onMemery. store ( value, for: key)
50
57
return value
51
58
}
52
59
53
60
@discardableResult
54
61
public func store( _ value: Value , for key: Key ) -> Task < Void , Never > {
55
- queueingLock. lock ( )
56
- defer { queueingLock. unlock ( ) }
57
- let oldTask = queueingTask
58
- let task = Task {
59
- await oldTask? . value
62
+ queueingTask. enqueueAndReplacing { [ weak self] in
63
+ guard let self else { return }
60
64
async let memory : Void = await onMemery. store ( value, for: key) . value
61
65
async let disk : Void = await _storeToDisk ( value, for: key)
62
66
63
67
await memory
64
68
await disk
65
69
}
66
- queueingTask = task
67
- return task
68
70
}
69
71
70
72
@discardableResult
71
73
public func remove( for key: Key ) -> Task < Void , Never > {
72
- queueingLock. lock ( )
73
- defer { queueingLock. unlock ( ) }
74
- let oldTask = queueingTask
75
- let task = Task {
76
- await oldTask? . value
74
+ queueingTask. enqueueAndReplacing { [ weak self] in
75
+ guard let self else { return }
77
76
async let memory : Void = await onMemery. remove ( for: key) . value
78
77
async let disk : Void = await onDisk. remove ( for: key) . value
79
78
80
79
await memory
81
80
await disk
82
81
}
83
- queueingTask = task
84
- return task
85
82
}
86
83
87
84
@discardableResult
88
85
public func removeAll( ) -> Task < Void , Never > {
89
- queueingLock. lock ( )
90
- defer { queueingLock. unlock ( ) }
91
- let oldTask = queueingTask
92
- let task = Task {
93
- await oldTask? . value
94
-
86
+ queueingTask. enqueueAndReplacing { [ weak self] in
87
+ guard let self else { return }
95
88
async let memory : Void = await onMemery. removeAll ( ) . value
96
89
async let disk : Void = await onDisk. removeAll ( ) . value
97
90
98
91
await memory
99
92
await disk
100
93
}
101
- queueingTask = task
102
- return task
103
94
}
104
95
105
- public func url( for key: Key ) -> URL ? {
106
- onDisk. url ( for: key)
96
+ public func url( for key: Key ) async -> URL ? {
97
+ await onDisk. url ( for: key)
107
98
}
108
99
}
109
100
0 commit comments