Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,11 @@ import PackageDescription
let package = Package(
name: "DataCacheKit",
platforms: [
.iOS(.v14),
.tvOS(.v14),
.watchOS(.v8),
.macOS(.v12)
.iOS(.v16),
.tvOS(.v16),
.watchOS(.v9),
.visionOS(.v2),
.macOS(.v13)
],
products: [
// Products define the executables and libraries a package produces, and make them visible to other packages.
Expand Down
55 changes: 23 additions & 32 deletions Sources/DataCacheKit/Cache.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import Foundation
import OSLog

public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: Caching, @unchecked Sendable {
public typealias Options = (forMemory: MemoryCache<Key, Value>.Options, forDisk: DiskCache<Key>.Options)
public actor Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: Caching {
public struct Options: Sendable {
public let forMemory: MemoryCache<Key, Value>.Options
public let forDisk: DiskCache<Key>.Options

public init(forMemory: MemoryCache<Key, Value>.Options, forDisk: DiskCache<Key>.Options) {
self.forMemory = forMemory
self.forDisk = forDisk
}
}

public let options: Options
public let logger: Logger
public nonisolated let options: Options
public nonisolated let logger: Logger

public subscript (key: Key) -> Value? {
get async throws {
Expand All @@ -16,7 +24,6 @@ public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: C
private let onMemery: MemoryCache<Key, Value>
private let onDisk: DiskCache<Key>

private let queueingLock = NSLock()
private var queueingTask: Task<Void, Never>?

public init(options: Options, logger: Logger = .init(.disabled)) {
Expand All @@ -26,8 +33,8 @@ public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: C
self.logger = logger
}

public func prepare() throws {
try onDisk.prepare()
public func prepare() async throws {
try await onDisk.prepare()
}

public func value(for key: Key) async throws -> Value? {
Expand All @@ -46,64 +53,48 @@ public final class Cache<Key: Hashable & Sendable, Value: Codable & Sendable>: C
return try decoder.decode(Value.self, from: data)
}()

onMemery.store(value, for: key)
await onMemery.store(value, for: key)
return value
}

@discardableResult
public func store(_ value: Value, for key: Key) -> Task<Void, Never> {
queueingLock.lock()
defer { queueingLock.unlock() }
let oldTask = queueingTask
let task = Task {
await oldTask?.value
queueingTask.enqueueAndReplacing { [weak self] in
guard let self else { return }
async let memory: Void = await onMemery.store(value, for: key).value
async let disk: Void = await _storeToDisk(value, for: key)

await memory
await disk
}
queueingTask = task
return task
}

@discardableResult
public func remove(for key: Key) -> Task<Void, Never> {
queueingLock.lock()
defer { queueingLock.unlock() }
let oldTask = queueingTask
let task = Task {
await oldTask?.value
queueingTask.enqueueAndReplacing { [weak self] in
guard let self else { return }
async let memory: Void = await onMemery.remove(for: key).value
async let disk: Void = await onDisk.remove(for: key).value

await memory
await disk
}
queueingTask = task
return task
}

@discardableResult
public func removeAll() -> Task<Void, Never> {
queueingLock.lock()
defer { queueingLock.unlock() }
let oldTask = queueingTask
let task = Task {
await oldTask?.value

queueingTask.enqueueAndReplacing { [weak self] in
guard let self else { return }
async let memory: Void = await onMemery.removeAll().value
async let disk: Void = await onDisk.removeAll().value

await memory
await disk
}
queueingTask = task
return task
}

public func url(for key: Key) -> URL? {
onDisk.url(for: key)
public func url(for key: Key) async -> URL? {
await onDisk.url(for: key)
}
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/DataCacheKit/Caching.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Foundation

public protocol Caching<Key, Value>: Sendable {
public protocol Caching<Key, Value>: Actor {
associatedtype Key: Hashable & Sendable
associatedtype Value

Expand Down
4 changes: 2 additions & 2 deletions Sources/DataCacheKit/DiskCache+Options.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import Foundation
import CommonCrypto

extension DiskCache {
public struct Options {
public struct Options: Sendable {
public var sizeLimit: Int
public var filename: @Sendable (Key) -> String?
public var path: Path
public var expirationTimeout: TimeInterval?

public enum Path {
public enum Path: Sendable {
case `default`(name: String)
case custom(URL)
}
Expand Down
Loading