Skip to content

Commit

Permalink
Added sendable conformances, and declared transactions to be non-esca…
Browse files Browse the repository at this point in the history
…ping

Fixes #205
  • Loading branch information
dimitribouniol committed May 20, 2024
1 parent 0852b8e commit a7f1af9
Show file tree
Hide file tree
Showing 38 changed files with 359 additions and 268 deletions.
10 changes: 8 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ let package = Package(
),
],
dependencies: [
.package(url: "https://github.com/mochidev/AsyncSequenceReader.git", .upToNextMinor(from: "0.1.2")),
.package(url: "https://github.com/mochidev/AsyncSequenceReader.git", .upToNextMinor(from: "0.2.1")),
.package(url: "https://github.com/mochidev/Bytes.git", .upToNextMinor(from: "0.3.0")),
],
targets: [
Expand All @@ -27,11 +27,17 @@ let package = Package(
dependencies: [
"AsyncSequenceReader",
"Bytes"
],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
]
),
.testTarget(
name: "CodableDatastoreTests",
dependencies: ["CodableDatastore"]
dependencies: ["CodableDatastore"],
swiftSettings: [
.enableExperimentalFeature("StrictConcurrency")
]
),
]
)
2 changes: 1 addition & 1 deletion Sources/CodableDatastore/Datastore/Configuration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2023 Mochi Development, Inc. All rights reserved.
//

public struct Configuration {
public struct Configuration: Sendable {
/// The size of a single page of data on disk and in memory.
///
/// Applications that deal with large objects may want to consider increasing this appropriately,
Expand Down
154 changes: 83 additions & 71 deletions Sources/CodableDatastore/Datastore/Datastore.swift

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions Sources/CodableDatastore/Datastore/DatastoreDescriptor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
/// A description of a ``Datastore``'s requirements of a persistence.
///
/// A persistence is expected to save a description and retrieve it when a connected ``Datastore`` requests it. The ``Datastore`` then uses it to compute if indexes need to be invalidated or re-built.
public struct DatastoreDescriptor: Equatable, Hashable {
public struct DatastoreDescriptor: Equatable, Hashable, Sendable {
/// The version that was current at time of serialization.
///
/// If a ``Datastore`` cannot decode this version, the datastore is presumed inaccessible, and any reads or writes will fail.
Expand Down Expand Up @@ -96,7 +96,7 @@ extension DatastoreDescriptor {
/// A description of an Index used by a ``Datastore``.
///
/// This information is used to determine which indexes must be invalidated or re-built, and which can be used as is. Additionally, it informs which properties must be reported along with any writes to keep existing indexes up to date.
public struct IndexDescriptor: Codable, Equatable, Hashable, Comparable {
public struct IndexDescriptor: Codable, Equatable, Hashable, Comparable, Sendable {
/// The version that was first used to persist an index to disk.
///
/// This is used to determine if an index must be re-built purely because something about how the index changed in a way that could not be automatically determined, such as Codable conformance changing.
Expand Down
8 changes: 4 additions & 4 deletions Sources/CodableDatastore/Datastore/DatastoreFormat.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,21 +73,21 @@ import Foundation
/// - Note: If your ``Instance`` type is ``/Swift/Identifiable``, you should _not_ declare an index for `id` — special accessors are created on your behalf that can be used instead.
///
/// - Important: We discourage declaring non-static stored and computed properties on your conforming type, as that will polute the key-path namespace of the format which is used for generating getters on the datastore.
public protocol DatastoreFormat<Version, Instance, Identifier> {
public protocol DatastoreFormat<Version, Instance, Identifier>: Sendable {
/// A type representing the version of the datastore on disk.
///
/// Best represented as an enum, this represents the every single version of the datastore you wish to be able to decode from disk. Assign a new version any time the codable representation or the representation of indexes is no longer backwards compatible.
///
/// The various ``Datastore`` initializers take a disctionary that maps between these versions and the most up-to-date Instance type, and will provide an opportunity to use legacy representations to decode the data to the expected type.
associatedtype Version: RawRepresentable & Hashable & CaseIterable where Version.RawValue: Indexable & Comparable
associatedtype Version: RawRepresentable & Hashable & CaseIterable & Sendable where Version.RawValue: Indexable & Comparable

/// The most up-to-date representation you use in your codebase.
associatedtype Instance: Codable
associatedtype Instance: Codable & Sendable

/// The identifier to be used when de-duplicating instances saved in the persistence.
///
/// Although ``Instance`` does _not_ need to be ``Identifiable``, a consistent identifier must still be provided for every instance to retrive and persist them. This identifier can be different from `Instance.ID` if truly necessary, though most conformers can simply set it to `Instance.ID`
associatedtype Identifier: Indexable & DiscreteIndexable
associatedtype Identifier: Indexable & DiscreteIndexable & Sendable

/// A default initializer creating a format instance the datastore can use for evaluation.
init()
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodableDatastore/Datastore/DatastoreKey.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
// Copyright © 2023 Mochi Development, Inc. All rights reserved.
//

public struct DatastoreKey: RawRepresentable, Hashable, Comparable {
public struct DatastoreKey: RawRepresentable, Hashable, Comparable, Sendable {
public var rawValue: String

public init(rawValue: String) {
Expand Down
3 changes: 2 additions & 1 deletion Sources/CodableDatastore/Datastore/ObservedEvent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ public enum ObservedEvent<IdentifierType, Entry> {
}

extension ObservedEvent: Identifiable where IdentifierType: Hashable {}
extension ObservedEvent: Sendable where IdentifierType: Sendable, Entry: Sendable {}

public struct ObservationEntry {
public struct ObservationEntry: Sendable {
var versionData: Data
var instanceData: Data
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/CodableDatastore/Datastore/Progress.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@

import Foundation

public typealias ProgressHandler = (_ progress: Progress) -> Void
public typealias ProgressHandler = @Sendable (_ progress: Progress) -> Void

public enum Progress {
public enum Progress: Sendable {
case evaluating
case working(current: Int, total: Int)
case complete(total: Int)
Expand Down
2 changes: 1 addition & 1 deletion Sources/CodableDatastore/Debug/GlobalTimer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
actor GlobalTimer {
var totalTime: TimeInterval = 0
var totalSamples: Int = 0
static var global = GlobalTimer()
static let global = GlobalTimer()

func submit(time: TimeInterval, sampleRate: Int = 100) {
precondition(sampleRate > 0)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

/// A helper type for passing around metadata about an index.
public struct GeneratedIndexRepresentation<Instance> {
public struct GeneratedIndexRepresentation<Instance: Sendable>: Sendable {
/// The name the index should be serialized under.
public var indexName: IndexName

Expand Down
2 changes: 1 addition & 1 deletion Sources/CodableDatastore/Indexes/IndexName.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
//

/// A typed name that an index is keyed under. This is typically the path component of the key path that leads to an index.
public struct IndexName: RawRepresentable, Hashable, Comparable {
public struct IndexName: RawRepresentable, Hashable, Comparable, Sendable {
public var rawValue: String

public init(rawValue: String) {
Expand Down
12 changes: 7 additions & 5 deletions Sources/CodableDatastore/Indexes/IndexRangeExpression.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public enum RangeBoundExpression<Bound: Comparable>: Equatable {
extension RangeBoundExpression: Sendable where Bound: Sendable { }

/// The order a range is declared in.
public enum RangeOrder: Equatable {
public enum RangeOrder: Equatable, Sendable {
/// The range is in ascending order.
case ascending

Expand Down Expand Up @@ -60,7 +60,7 @@ extension IndexRangeExpression {
)
}

func applying(_ newOrder: RangeOrder) -> some IndexRangeExpression<Bound> {
func applying(_ newOrder: RangeOrder) -> IndexRange<Bound> {
IndexRange(
lower: lowerBoundExpression,
upper: upperBoundExpression,
Expand All @@ -74,7 +74,7 @@ extension IndexRangeExpression {
}

/// The position relative to a range.
public enum RangePosition: Equatable {
public enum RangePosition: Equatable, Sendable {
/// A value appears before the range.
case before

Expand Down Expand Up @@ -189,6 +189,8 @@ public struct IndexRange<Bound: Comparable>: IndexRangeExpression {
}
}

extension IndexRange: Sendable where Bound: Sendable {}

extension IndexRange where Bound == Never {
static let unbounded = IndexRange()
}
Expand All @@ -199,7 +201,7 @@ postfix operator ..>
extension Comparable {
/// A range excluding the lower bound.
@inlinable
public static func ..> (minimum: Self, maximum: Self) -> some IndexRangeExpression<Self> {
public static func ..> (minimum: Self, maximum: Self) -> IndexRange<Self> {
precondition(minimum == minimum, "Range cannot have an unordered lower bound.")
precondition(maximum == maximum, "Range cannot have an unordered upper bound.")
precondition(minimum <= maximum, "Range lower bound must be less than upper bound.")
Expand All @@ -211,7 +213,7 @@ extension Comparable {

/// A partial range excluding the lower bound.
@inlinable
public static postfix func ..> (minimum: Self) -> some IndexRangeExpression<Self> {
public static postfix func ..> (minimum: Self) -> IndexRange<Self> {
precondition(minimum == minimum, "Range cannot have an unordered lower bound.")
return IndexRange(
lower: .excluding(minimum),
Expand Down
Loading

0 comments on commit a7f1af9

Please sign in to comment.