Skip to content

more Sendable conformances & Sendable Context #381

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 8, 2023
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
2 changes: 2 additions & 0 deletions Sources/TSCBasic/CodableResult.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ public struct CodableResult<Success, Failure>: Codable where Success: Codable, F
}
}

extension CodableResult: Sendable where Success: Sendable, Failure: Sendable {}

extension CodableResult where Failure == StringError {
public init(body: () throws -> Success) {
do {
Expand Down
4 changes: 4 additions & 0 deletions Sources/TSCBasic/Condition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,7 @@ public struct Condition {
return try body()
}
}

#if compiler(>=5.7)
extension Condition: Sendable {}
#endif
2 changes: 1 addition & 1 deletion Sources/TSCBasic/DeltaAlgorithm.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
/// It is not an error to provide a predicate that does not satisfy these
/// requirements, and the algorithm will generally produce reasonable results.
/// However, it may run substantially more tests than with a good predicate.
public struct DeltaAlgorithm<Change: Hashable> {
public struct DeltaAlgorithm<Change: Hashable>: Sendable {

public init() {}

Expand Down
8 changes: 4 additions & 4 deletions Sources/TSCBasic/DiagnosticsEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ extension DiagnosticData {
public protocol DiagnosticLocation: Sendable, CustomStringConvertible {
}

public struct Diagnostic: CustomStringConvertible {
public struct Diagnostic: CustomStringConvertible, Sendable {
/// The behavior associated with this diagnostic.
public enum Behavior {
public enum Behavior: Sendable {
/// An error which will halt the operation.
case error

Expand All @@ -38,7 +38,7 @@ public struct Diagnostic: CustomStringConvertible {
case ignored
}

public struct Message {
public struct Message: Sendable {
/// The diagnostic's behavior.
public let behavior: Behavior

Expand Down Expand Up @@ -191,7 +191,7 @@ extension Diagnostic.Message {
}
}

public struct StringDiagnostic: DiagnosticData {
public struct StringDiagnostic: DiagnosticData, Sendable {
/// The diagnostic description.
public let description: String

Expand Down
4 changes: 2 additions & 2 deletions Sources/TSCBasic/FileSystem.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import Foundation
import Dispatch
import SystemPackage

public struct FileSystemError: Error, Equatable {
public enum Kind: Equatable {
public struct FileSystemError: Error, Equatable, Sendable {
public enum Kind: Equatable, Sendable {
/// Access to the path is denied.
///
/// This is used when an operation cannot be completed because a component of
Expand Down
6 changes: 3 additions & 3 deletions Sources/TSCBasic/HashAlgorithms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import CryptoKit
#endif

public protocol HashAlgorithm {
public protocol HashAlgorithm: Sendable {

/// Hashes the input bytes, returning the digest.
///
Expand All @@ -31,7 +31,7 @@ extension HashAlgorithm {
/// SHA-256 implementation from Secure Hash Algorithm 2 (SHA-2) set of
/// cryptographic hash functions (FIPS PUB 180-2).
/// Uses CryptoKit where available
public struct SHA256: HashAlgorithm {
public struct SHA256: HashAlgorithm, Sendable {
private let underlying: HashAlgorithm

public init() {
Expand Down Expand Up @@ -197,7 +197,7 @@ struct InternalSHA256: HashAlgorithm {
#if canImport(CryptoKit)
@available(*, deprecated, message: "use SHA256 which abstract over platform differences")
@available(macOS 10.15, iOS 13, tvOS 13, watchOS 6, *)
public struct CryptoKitSHA256: HashAlgorithm {
public struct CryptoKitSHA256: HashAlgorithm, Sendable {
let underlying = _CryptoKitSHA256()
public init() {}
public func hash(_ bytes: ByteString) -> ByteString {
Expand Down
2 changes: 2 additions & 0 deletions Sources/TSCBasic/KeyedPair.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ public struct KeyedPair<T, K: Hashable>: Hashable {
return lhs.key == rhs.key
}
}

extension KeyedPair: Sendable where T: Sendable, K: Sendable {}
6 changes: 6 additions & 0 deletions Sources/TSCBasic/LazyCache.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import class Foundation.NSLock
/// ```
///
/// See: https://bugs.swift.org/browse/SR-1042
@available(*, deprecated, message: "This implementation does not work -- https://github.com/apple/swift-tools-support-core/issues/385")
public struct LazyCache<Class, T> {
// FIXME: It would be nice to avoid a per-instance lock, but this type isn't
// intended for creating large numbers of instances of. We also really want
Expand Down Expand Up @@ -57,3 +58,8 @@ public struct LazyCache<Class, T> {
}
}
}

#if swift(>=5.6)
@available(*, unavailable) // until https://github.com/apple/swift-tools-support-core/issues/385 is fixed
extension LazyCache: Sendable {}
#endif
2 changes: 2 additions & 0 deletions Sources/TSCBasic/OrderedDictionary.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,5 @@ extension OrderedDictionary: RandomAccessCollection {
return (key, value)
}
}

extension OrderedDictionary: Sendable where Key: Sendable, Value: Sendable {}
2 changes: 2 additions & 0 deletions Sources/TSCBasic/OrderedSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,5 @@ public func == <T>(lhs: OrderedSet<T>, rhs: OrderedSet<T>) -> Bool {
}

extension OrderedSet: Hashable where Element: Hashable { }

extension OrderedSet: Sendable where Element: Sendable { }
2 changes: 2 additions & 0 deletions Sources/TSCBasic/misc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ public struct CodableRange<Bound> where Bound: Comparable & Codable {
}
}

extension CodableRange: Sendable where Bound: Sendable {}

extension CodableRange: Codable {
private enum CodingKeys: String, CodingKey {
case lowerBound, upperBound
Expand Down
121 changes: 119 additions & 2 deletions Sources/TSCUtility/Context.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,127 @@
*/

import Foundation
import _Concurrency

/// Typealias for an any typed dictionary for arbitrary usage to store context.
public typealias Context = [ObjectIdentifier: Any]

public struct Context {
private var backing: [ObjectIdentifier: Any] = [:]

#if compiler(>=5.5.2)
@available(*, deprecated, message: "Values should be Sendable")
@_disfavoredOverload
public init(dictionaryLiteral keyValuePairs: (ObjectIdentifier, Any)...) {
self.backing = Dictionary(uniqueKeysWithValues: keyValuePairs)
}

public init(dictionaryLiteral keyValuePairs: (ObjectIdentifier, Sendable)...) {
self.backing = Dictionary(uniqueKeysWithValues: keyValuePairs)
}

@available(*, deprecated, message: "Values should be Sendable")
@_disfavoredOverload
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

one of my favorite tricks :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakepetroules at some point we'll need @_overloadFavouriteness(10) if we have need more than one level ;)

public subscript(key: ObjectIdentifier) -> Any? {
get {
return self.backing[key]
}
set {
self.backing[key] = newValue
}
}

public subscript<Value>(key: ObjectIdentifier, as type: Value.Type = Value.self) -> Value? where Value: Sendable {
get {
return self.backing[key] as? Value
}
set {
self.backing[key] = newValue
}
}
#else
public init(dictionaryLiteral keyValuePairs: (ObjectIdentifier, Any)...) {
self.backing = Dictionary(uniqueKeysWithValues: keyValuePairs)
}

@_disfavoredOverload
public subscript(key: ObjectIdentifier) -> Any? {
get {
return self.backing[key]
}
set {
self.backing[key] = newValue
}
}

public subscript<Value>(key: ObjectIdentifier, as type: Value.Type = Value.self) -> Value? {
get {
return self.backing[key] as? Value
}
set {
self.backing[key] = newValue
}
}
#endif
}

#if compiler(>=5.7)
extension Context: /* until we can remove the support for 'Any' values */ @unchecked Sendable {}
#else
#if compiler(>=5.5.2)
extension Context: UnsafeSendable {}
#endif
#endif

@available(*, deprecated, renamed: "init()")
extension Context: ExpressibleByDictionaryLiteral {
public typealias Key = ObjectIdentifier
public typealias Value = Any
}

extension Context {
#if compiler(>=5.5.2)
/// Get the value for the given type.
@available(*, deprecated, message: "Values should be Sendable")
@_disfavoredOverload
public func get<T>(_ type: T.Type = T.self) -> T {
guard let value = getOptional(type) else {
fatalError("no type \(T.self) in context")
}
return value
}

public func get<T: Sendable>(_ type: T.Type = T.self) -> T {
guard let value = self.getOptional(type) else {
fatalError("no type \(T.self) in context")
}
return value
}

/// Get the value for the given type, if present.
@available(*, deprecated, message: "Values should be Sendable")
@_disfavoredOverload
public func getOptional<T>(_ type: T.Type = T.self) -> T? {
guard let value = self[ObjectIdentifier(T.self)] else {
return nil
}
return value as? T
}

/// Get the value for the given type, if present.
public func getOptional<T: Sendable>(_ type: T.Type = T.self) -> T? {
return self[ObjectIdentifier(T.self)]
}

/// Set a context value for a type.
@available(*, deprecated, message: "Values should be Sendable")
@_disfavoredOverload
public mutating func set<T>(_ value: T) {
self[ObjectIdentifier(T.self)] = value
}

public mutating func set<Value: Sendable>(_ value: Value) {
self[ObjectIdentifier(Value.self)] = value
}
#else
/// Get the value for the given type.
public func get<T>(_ type: T.Type = T.self) -> T {
guard let value = getOptional(type) else {
Expand All @@ -34,4 +150,5 @@ extension Context {
public mutating func set<T>(_ value: T) {
self[ObjectIdentifier(T.self)] = value
}
#endif
}
12 changes: 9 additions & 3 deletions Sources/TSCUtility/SerializedDiagnostics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Foundation
import TSCBasic

/// Represents diagnostics serialized in a .dia file by the Swift compiler or Clang.
public struct SerializedDiagnostics {
public struct SerializedDiagnostics: Sendable {
public enum Error: Swift.Error {
case badMagic
case unexpectedTopLevelRecord
Expand Down Expand Up @@ -61,7 +61,7 @@ extension SerializedDiagnostics.Error: CustomNSError {
extension SerializedDiagnostics {
public struct Diagnostic {

public enum Level: UInt64 {
public enum Level: UInt64, Sendable {
case ignored, note, warning, error, fatal, remark
}
/// The diagnostic message text.
Expand Down Expand Up @@ -168,7 +168,7 @@ extension SerializedDiagnostics {
}
}

public struct FixIt {
public struct FixIt: Sendable {
/// Start location.
public var start: SourceLocation
/// End location.
Expand All @@ -178,6 +178,12 @@ extension SerializedDiagnostics {
}
}

#if compiler(>=5.7)
extension SerializedDiagnostics.Diagnostic: Sendable {}
#else
extension SerializedDiagnostics.Diagnostic: UnsafeSendable {}
#endif

extension SerializedDiagnostics {
private struct Reader: BitstreamVisitor {
var diagnosticRecords: [[OwnedRecord]] = []
Expand Down
39 changes: 30 additions & 9 deletions Sources/TSCUtility/Tracing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

import Foundation

public enum TracingEventType: String, Codable {
public enum TracingEventType: String, Codable, Sendable {
case asyncBegin
case asyncEnd
}
Expand Down Expand Up @@ -51,7 +51,7 @@ public protocol TracingEventProtocol {
)
}

public protocol TracingCollectionProtocol {
public protocol TracingCollectionProtocol: Sendable {
var events: [TracingEventProtocol] { get set }
init(_ events: [TracingEventProtocol])
}
Expand All @@ -62,7 +62,7 @@ extension TracingCollectionProtocol {
}
}

public struct TracingEvent: TracingEventProtocol, Codable {
public struct TracingEvent: TracingEventProtocol, Codable, Sendable {
public let cat: String
public let name: String
public let id: String
Expand Down Expand Up @@ -135,13 +135,37 @@ public struct TracingEvent: TracingEventProtocol, Codable {
#endif
}

public class TracingCollection: TracingCollectionProtocol {
public var events: [TracingEventProtocol] = []
public final class TracingCollection {
private let lock = NSLock()
private var _events: [TracingEventProtocol] = []

public var events: [TracingEventProtocol] {
get {
return self.lock.withLock {
self._events
}
}

set {
self.lock.withLock {
self._events = newValue
}
}
}

public required init(_ events: [TracingEventProtocol] = []) {
self.events = events
}
}

#if compiler(>=5.7)
extension TracingCollection: @unchecked /* because self-locked */ Sendable {}
extension TracingCollection: TracingCollectionProtocol {}
#else
extension TracingCollection: UnsafeSendable {}
extension TracingCollection: TracingCollectionProtocol {}
#endif

extension Context {
public static func withTracing(_ collection: TracingCollectionProtocol) -> Context {
return Context(dictionaryLiteral: (ObjectIdentifier(TracingCollectionProtocol.self), collection as Any))
Expand All @@ -154,10 +178,7 @@ extension Context {

public var tracing: TracingCollectionProtocol? {
get {
guard let collection = self[ObjectIdentifier(TracingCollectionProtocol.self)] as? TracingCollectionProtocol else {
return nil
}
return collection
return self[ObjectIdentifier(TracingCollectionProtocol.self), as: TracingCollectionProtocol.self]
}
set {
self[ObjectIdentifier(TracingCollectionProtocol.self)] = newValue
Expand Down
Loading