diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..c1a2cfc --- /dev/null +++ b/Package.resolved @@ -0,0 +1,33 @@ +{ + "originHash" : "34cbc493f77f3125d8e5ee71eaf10a961a63d68471367996e3880e96a237e7f2", + "pins" : [ + { + "identity" : "swallow", + "kind" : "remoteSourceControl", + "location" : "https://github.com/vmanot/Swallow.git", + "state" : { + "branch" : "master", + "revision" : "6227a1114e341daf54e90df61e173599b187a9b1" + } + }, + { + "identity" : "swift-collections", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-collections", + "state" : { + "revision" : "671108c96644956dddcd89dd59c203dcdb36cec7", + "version" : "1.1.4" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", + "version" : "510.0.3" + } + } + ], + "version" : 3 +} diff --git a/Sources/Merge/Intermodular/Protocol Conformances/Dispatch/Dispatch+Mutex.swift b/Sources/Merge/Intermodular/Protocol Conformances/Dispatch/Dispatch+Mutex.swift index 1e6d292..bc03f47 100644 --- a/Sources/Merge/Intermodular/Protocol Conformances/Dispatch/Dispatch+Mutex.swift +++ b/Sources/Merge/Intermodular/Protocol Conformances/Dispatch/Dispatch+Mutex.swift @@ -5,7 +5,7 @@ import Dispatch import Swallow -public struct DispatchMutexDevice: ScopedReadWriteMutex, @unchecked Sendable { +public struct DispatchMutexDevice: ScopedReadWriteMutexProtocol, @unchecked Sendable { @MutexProtected private var queue: DispatchQueue diff --git a/Sources/Merge/Intramodular (WIP)/Actor Effects/_ActorSideEffect.swift b/Sources/Merge/Intramodular (WIP)/Actor Effects/_ActorSideEffect.swift index d0369c2..7966f65 100644 --- a/Sources/Merge/Intramodular (WIP)/Actor Effects/_ActorSideEffect.swift +++ b/Sources/Merge/Intramodular (WIP)/Actor Effects/_ActorSideEffect.swift @@ -39,17 +39,17 @@ extension _ActorSideEffectSpecification { } } -public struct TaskEffectSpecifications { - public enum _TaskEffectSpecificationSymbol { +public struct _ActorSideEffectsSpecifications { + public enum _ActorSideEffectSpecificationSymbol { case keyPath(AnyKeyPath) } /// Apply an effect on the change of something. public struct OnChange: _ActorSideEffectSpecification { - public let value: _TaskEffectSpecificationSymbol + public let value: _ActorSideEffectSpecificationSymbol public let content: Content - init(value: _TaskEffectSpecificationSymbol, content: Content) { + init(value: _ActorSideEffectSpecificationSymbol, content: Content) { self.value = value self.content = content } diff --git a/Sources/Merge/Intramodular/Observable Tasks/Foundation/PassthroughTask.swift b/Sources/Merge/Intramodular/Observable Tasks/Foundation/PassthroughTask.swift index a2003e1..9c9a9a5 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/Foundation/PassthroughTask.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/Foundation/PassthroughTask.swift @@ -53,7 +53,7 @@ open class PassthroughTask: ObservableTask { status: Status, _objectWillChange: ObservableObjectPublisher ) { - guard TaskStatusDescription(status) != TaskStatusDescription(_status) else { + guard ObservableTaskStatusDescription(status) != ObservableTaskStatusDescription(_status) else { return } diff --git a/Sources/Merge/Intramodular/Observable Tasks/Foundation/TaskSuccessPublisher.swift b/Sources/Merge/Intramodular/Observable Tasks/Foundation/TaskSuccessPublisher.swift index e3cae0d..6b526bd 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/Foundation/TaskSuccessPublisher.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/Foundation/TaskSuccessPublisher.swift @@ -24,7 +24,7 @@ public struct TaskSuccessPublisher { extension TaskSuccessPublisher: SingleOutputPublisher { public typealias Output = Upstream.Success - public typealias Failure = TaskFailure + public typealias Failure = ObservableTaskFailure } // MARK: - API diff --git a/Sources/Merge/Intramodular/Observable Tasks/ObservableTask.swift b/Sources/Merge/Intramodular/Observable Tasks/ObservableTask.swift index 209b10e..41c6267 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/ObservableTask.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/ObservableTask.swift @@ -23,7 +23,7 @@ public protocol ObservableTask: Cancellable, Identifiable, Objec } extension ObservableTask { - public var statusDescription: TaskStatusDescription { + public var statusDescription: ObservableTaskStatusDescription { .init(status) } } diff --git a/Sources/Merge/Intramodular/Observable Tasks/ObservableTaskOutputPublisher.swift b/Sources/Merge/Intramodular/Observable Tasks/ObservableTaskOutputPublisher.swift index 0a4f057..b72baf4 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/ObservableTaskOutputPublisher.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/ObservableTaskOutputPublisher.swift @@ -8,7 +8,7 @@ import Swallow public struct ObservableTaskOutputPublisher: Publisher { public typealias Output = TaskOutput - public typealias Failure = TaskFailure + public typealias Failure = ObservableTaskFailure private let base: Base diff --git a/Sources/Merge/Intramodular/Observable Tasks/OpaqueObservableTask.swift b/Sources/Merge/Intramodular/Observable Tasks/OpaqueObservableTask.swift index 27b0be5..8a2a13b 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/OpaqueObservableTask.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/OpaqueObservableTask.swift @@ -6,7 +6,7 @@ import Runtime import Swallow public final class OpaqueObservableTask: CustomStringConvertible, ObjCObject, ObservableTask { - public typealias StatusDescription = TaskStatusDescription + public typealias StatusDescription = ObservableTaskStatusDescription public typealias Success = Any public typealias Error = Swift.Error diff --git a/Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatus.swift b/Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatus.swift index 1d9e799..8fad9c3 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatus.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatus.swift @@ -34,15 +34,15 @@ extension ObservableTaskStatus { } public var isOutput: Bool { - TaskStatusDescription(self).isOutput + ObservableTaskStatusDescription(self).isOutput } public var isFailure: Bool { - TaskStatusDescription(self).isFailure + ObservableTaskStatusDescription(self).isFailure } public var isCompletion: Bool { - TaskStatusDescription(self).isCompletion + ObservableTaskStatusDescription(self).isCompletion } } @@ -85,7 +85,7 @@ extension ObservableTaskStatus { } } - public var failure: TaskFailure? { + public var failure: ObservableTaskFailure? { switch self { case .canceled: return .canceled @@ -96,7 +96,7 @@ extension ObservableTaskStatus { } } - public init(_ failure: TaskFailure) { + public init(_ failure: ObservableTaskFailure) { switch failure { case .canceled: self = .canceled @@ -297,7 +297,7 @@ extension ObservableTaskStatus { } } - public init(_ status: Result, TaskFailure>) { + public init(_ status: Result, ObservableTaskFailure>) { switch status { case .success(let output): do { switch output { @@ -331,10 +331,3 @@ extension Result { } } } - -// MARK: - Deprecated - -@available(*, deprecated, renamed: "ObservableTaskStatusType") -public typealias TaskStatusType = ObservableTaskStatusType -@available(*, deprecated, renamed: "ObservableTaskStatus") -public typealias TaskStatus = ObservableTaskStatus diff --git a/Sources/Merge/Intramodular/Observable Tasks/Status/TaskStatusDescription.swift b/Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatusDescription.swift similarity index 86% rename from Sources/Merge/Intramodular/Observable Tasks/Status/TaskStatusDescription.swift rename to Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatusDescription.swift index f541c44..ce82d32 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/Status/TaskStatusDescription.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/Status/ObservableTaskStatusDescription.swift @@ -7,7 +7,7 @@ import Swallow import SwiftUI @frozen -public enum TaskStatusDescription: CustomDebugStringConvertible, Hashable { +public enum ObservableTaskStatusDescription: CustomDebugStringConvertible, Hashable { case idle case active case paused @@ -33,7 +33,7 @@ public enum TaskStatusDescription: CustomDebugStringConvertible, Hashable { } } -extension TaskStatusDescription { +extension ObservableTaskStatusDescription { public var isTerminal: Bool { switch self { case .success, .canceled, .error: @@ -66,7 +66,7 @@ extension TaskStatusDescription { } } -extension TaskStatusDescription { +extension ObservableTaskStatusDescription { public var isCompletion: Bool { switch self { case .idle, .active, .paused: @@ -77,7 +77,7 @@ extension TaskStatusDescription { } } -extension TaskStatusDescription { +extension ObservableTaskStatusDescription { public var isActive: Bool { switch self { case .active: @@ -124,7 +124,7 @@ extension TaskStatusDescription { // MARK: - Auxiliary -extension TaskStatusDescription { +extension ObservableTaskStatusDescription { public enum Comparison { case idle case active @@ -132,7 +132,7 @@ extension TaskStatusDescription { case failure public static func == ( - lhs: TaskStatusDescription?, + lhs: ObservableTaskStatusDescription?, rhs: Self ) -> Bool { if let lhs = lhs { @@ -165,7 +165,7 @@ extension TaskStatusDescription { } public static func != ( - lhs: TaskStatusDescription?, + lhs: ObservableTaskStatusDescription?, rhs: Self ) -> Bool { !(lhs == rhs) @@ -175,12 +175,12 @@ extension TaskStatusDescription { extension ObservableTaskStatus { @_disfavoredOverload - public static func == (lhs: Self, rhs: TaskStatusDescription.Comparison) -> Bool { - TaskStatusDescription(lhs) == rhs + public static func == (lhs: Self, rhs: ObservableTaskStatusDescription.Comparison) -> Bool { + ObservableTaskStatusDescription(lhs) == rhs } @_disfavoredOverload - public static func != (lhs: Self, rhs: TaskStatusDescription.Comparison) -> Bool { - TaskStatusDescription(lhs) != rhs + public static func != (lhs: Self, rhs: ObservableTaskStatusDescription.Comparison) -> Bool { + ObservableTaskStatusDescription(lhs) != rhs } } diff --git a/Sources/Merge/Intramodular/Observable Tasks/Status/TaskFailure.swift b/Sources/Merge/Intramodular/Observable Tasks/Status/TaskFailure.swift index 92dbecc..ba68ae5 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/Status/TaskFailure.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/Status/TaskFailure.swift @@ -8,7 +8,7 @@ import Swallow /// An enumeration that represents the source of task failure. @frozen -public enum TaskFailure: _ErrorX, HashEquatable { +public enum ObservableTaskFailure: _ErrorX, HashEquatable { case canceled case error(Error) @@ -43,7 +43,7 @@ public enum TaskFailure: _ErrorX, HashEquatable { // MARK: - Initializers -extension TaskFailure { +extension ObservableTaskFailure { public init?(_ status: ObservableTaskStatus) { if let failure = status.failure { self = failure @@ -56,7 +56,7 @@ extension TaskFailure { // MARK: - Supplementary extension AnyError { - public init(from failure: TaskFailure) { + public init(from failure: ObservableTaskFailure) { switch failure { case .canceled: self.init(erasing: CancellationError()) @@ -69,7 +69,7 @@ extension AnyError { extension Subscribers.Completion { public static func failure( _ error: Error - ) -> Self where Failure == TaskFailure { + ) -> Self where Failure == ObservableTaskFailure { .failure(.error(error)) } } diff --git a/Sources/Merge/Intramodular/Observable Tasks/Status/TaskResult.swift b/Sources/Merge/Intramodular/Observable Tasks/Status/TaskResult.swift index 33ec77d..c6bc6b1 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/Status/TaskResult.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/Status/TaskResult.swift @@ -35,7 +35,7 @@ public enum TaskResult { } } - public init?(from result: Result, TaskFailure>) { + public init?(from result: Result, ObservableTaskFailure>) { switch result { case .success(let output): guard let success = output.value else { diff --git a/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButton.swift b/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButton.swift index fa6e595..81d095d 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButton.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButton.swift @@ -66,7 +66,7 @@ public struct TaskButton: View { } } - private var displayTaskStatus: TaskStatusDescription { + private var displayTaskStatus: ObservableTaskStatusDescription { if let status = task?.statusDescription { return status } else { diff --git a/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonConfiguration.swift b/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonConfiguration.swift index ac84bc7..3d042a0 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonConfiguration.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonConfiguration.swift @@ -13,5 +13,5 @@ public struct TaskButtonConfiguration { public let isInterruptible: Bool public let isRestartable: Bool - public let status: TaskStatusDescription + public let status: ObservableTaskStatusDescription } diff --git a/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonStatus.swift b/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonStatus.swift index 1d3320a..4d020e2 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonStatus.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/SwiftUI/TaskButtonStatus.swift @@ -6,5 +6,5 @@ import Combine import Swift public struct TaskButtonStatus: Hashable { - public let description: TaskStatusDescription + public let description: ObservableTaskStatusDescription } diff --git a/Sources/Merge/Intramodular/Observable Tasks/_AnyObservableTaskGroup.swift b/Sources/Merge/Intramodular/Observable Tasks/_AnyObservableTaskGroup.swift index a301ce9..a677513 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/_AnyObservableTaskGroup.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/_AnyObservableTaskGroup.swift @@ -6,7 +6,7 @@ import Combine import Swallow public protocol _ObservableTaskGroupType: _CancellablesProviding, ObservableObject { - typealias TaskHistory = [TaskStatusDescription] + typealias TaskHistory = [ObservableTaskStatusDescription] associatedtype Key @@ -18,7 +18,7 @@ public protocol _ObservableTaskGroupType: _CancellablesProviding, ObservableObje @MainActor func _opaque_lastStatus( forCustomTaskIdentifier identifier: AnyHashable - ) throws -> TaskStatusDescription? + ) throws -> ObservableTaskStatusDescription? } public class _AnyObservableTaskGroup: ObservableObject { @@ -31,7 +31,7 @@ extension _ObservableTaskGroup { @MainActor public func _opaque_lastStatus( forCustomTaskIdentifier identifier: AnyHashable - ) throws -> TaskStatusDescription? { + ) throws -> ObservableTaskStatusDescription? { self.lastStatus(forCustomTaskIdentifier: try cast(identifier.base, to: Key.self)) } } diff --git a/Sources/Merge/Intramodular/Observable Tasks/_ObservableTaskGroup.swift b/Sources/Merge/Intramodular/Observable Tasks/_ObservableTaskGroup.swift index d7718c2..26da65c 100644 --- a/Sources/Merge/Intramodular/Observable Tasks/_ObservableTaskGroup.swift +++ b/Sources/Merge/Intramodular/Observable Tasks/_ObservableTaskGroup.swift @@ -156,7 +156,7 @@ extension _ObservableTaskGroup { public func lastStatus( forCustomTaskIdentifier identifier: CustomIdentifier - ) -> TaskStatusDescription? { + ) -> ObservableTaskStatusDescription? { guard keepHistory else { assertionFailure() @@ -194,7 +194,7 @@ extension _ObservableTaskGroup { @MainActor public func status( ofMostRecent action: Key - ) -> TaskStatusDescription? { + ) -> ObservableTaskStatusDescription? { if let status = self[customIdentifier: action].last?.statusDescription { return status } else { @@ -205,8 +205,8 @@ extension _ObservableTaskGroup { @MainActor public func status( ofMostRecent casePath: CasePath - ) -> TaskStatusDescription? { - return #try(.optimistic) { () -> TaskStatusDescription? in + ) -> ObservableTaskStatusDescription? { + return #try(.optimistic) { () -> ObservableTaskStatusDescription? in guard let id = try _customIdentifier(ofMostRecent: casePath) else { return nil } @@ -233,7 +233,7 @@ extension _ObservableTaskGroup: Sequence { fileprivate var source: Weak? public let customIdentifier: Key? - public let status: TaskStatusDescription? + public let status: ObservableTaskStatusDescription? public let history: TaskHistory public init( diff --git a/Sources/Merge/Intramodular/Process/OSAScriptProcess.swift b/Sources/Merge/Intramodular/Process/OSAScriptProcess.swift index e9a9579..97089e6 100644 --- a/Sources/Merge/Intramodular/Process/OSAScriptProcess.swift +++ b/Sources/Merge/Intramodular/Process/OSAScriptProcess.swift @@ -141,8 +141,12 @@ extension OSAScriptProcess { public static func _osascript_launchPathAndArguments( for executableURLAndArguments: (executableURL: URL?, arguments: [String]?) ) throws -> (launchPath: String, arguments: [String]) { + enum Error: Swift.Error { + case executablePathMissing + } + guard let executablePath: String = executableURLAndArguments.executableURL?.path else { - throw NSError(domain: "OSAScriptProcessError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Executable URL is not set."]) + throw Error.executablePathMissing } let argumentsString: String? diff --git a/Sources/Merge/Intramodular/Process/SystemShell.swift b/Sources/Merge/Intramodular/Process/SystemShell.swift index 4ceebc2..b891a55 100644 --- a/Sources/Merge/Intramodular/Process/SystemShell.swift +++ b/Sources/Merge/Intramodular/Process/SystemShell.swift @@ -63,32 +63,6 @@ extension SystemShell { return try await process.run() } } - -extension _AsyncProcess { - public convenience init( - command: String, - input: String? = nil, - shell: SystemShell.Environment = .zsh, - environment: [String: String]? = nil, - currentDirectoryURL: URL? = nil, - options: [_AsyncProcess.Option]? - ) async throws { - let (launchPath, arguments) = try await shell.resolve(command: command) - - try self.init( - executableURL: URL(fileURLWithPath: launchPath), - arguments: arguments, - environment: environment ?? ProcessInfo.processInfo.environment, - currentDirectoryURL: currentDirectoryURL, - options: options - ) - - if let input = input?.data(using: .utf8), !input.isEmpty, let handle = standardInputPipe?.fileHandleForWriting { - try? handle.write(contentsOf: input) - try? handle.close() - } - } -} #else @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) @available(macCatalyst, unavailable) @@ -125,6 +99,34 @@ public actor _ShellActor { public static let shared: ActorType = ActorType() } +#if os(macOS) +extension _AsyncProcess { + public convenience init( + command: String, + input: String? = nil, + shell: SystemShell.Environment = .zsh, + environment: [String: String]? = nil, + currentDirectoryURL: URL? = nil, + options: [_AsyncProcess.Option]? + ) async throws { + let (launchPath, arguments) = try await shell.resolve(command: command) + + try self.init( + executableURL: URL(fileURLWithPath: launchPath), + arguments: arguments, + environment: environment ?? ProcessInfo.processInfo.environment, + currentDirectoryURL: currentDirectoryURL, + options: options + ) + + if let input = input?.data(using: .utf8), !input.isEmpty, let handle = standardInputPipe?.fileHandleForWriting { + try? handle.write(contentsOf: input) + try? handle.close() + } + } +} +#endif + // MARK: - Deprecated @available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) diff --git a/Sources/Merge/Intramodular/Process/_AsyncProcess.swift b/Sources/Merge/Intramodular/Process/_AsyncProcess.swift index a0a2562..b0e4f3c 100644 --- a/Sources/Merge/Intramodular/Process/_AsyncProcess.swift +++ b/Sources/Merge/Intramodular/Process/_AsyncProcess.swift @@ -82,14 +82,31 @@ public class _AsyncProcess: Logging { process.executableURL = executableURL process.arguments = arguments - process.environment = environment + process.environment = environment ?? ProcessInfo.processInfo.environment process.currentDirectoryURL = currentDirectoryURL?._fromURLToFileURL() ?? process.currentDirectoryURL - + self.options = options _registerAndSetUpIO(existingProcess: nil) } + #else + public init() throws { + throw Never.Reason.unavailable + } + + + public init( + executableURL: URL?, + arguments: [String]?, + environment: [String: String]?, + currentDirectoryURL: URL?, + options: [_AsyncProcess.Option]? = nil + ) throws { + throw Never.Reason.unsupported + } + #endif + #if os(macOS) private func _registerAndSetUpIO(existingProcess: Process?) { Self.$runningProcesses.withCriticalRegion { $0.append(self) @@ -97,10 +114,6 @@ public class _AsyncProcess: Logging { _setUpStdinStdoutStderr(existingProcess: existingProcess) } - #else - public init() throws { - throw Never.Reason.unavailable - } #endif } diff --git a/Sources/Merge/Intramodular/WIP/TaskRetryDelayStrategy.swift b/Sources/Merge/Intramodular/Rate-limiting & Retrying/TaskRetryDelayStrategy.swift similarity index 98% rename from Sources/Merge/Intramodular/WIP/TaskRetryDelayStrategy.swift rename to Sources/Merge/Intramodular/Rate-limiting & Retrying/TaskRetryDelayStrategy.swift index f54bc86..a07d9a5 100644 --- a/Sources/Merge/Intramodular/WIP/TaskRetryDelayStrategy.swift +++ b/Sources/Merge/Intramodular/Rate-limiting & Retrying/TaskRetryDelayStrategy.swift @@ -13,7 +13,7 @@ public protocol TaskRetryDelayStrategy: Hashable, Sendable { ) -> Duration } -// MARK: - Implemented Conformances +// MARK: - Standard Implementations @available(macOS 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) public struct LinearBackoffStrategy: TaskRetryDelayStrategy { diff --git a/Sources/Merge/Intramodular/WIP/_TaskRetryPolicy.swift b/Sources/Merge/Intramodular/Rate-limiting & Retrying/_TaskRetryPolicy.swift similarity index 100% rename from Sources/Merge/Intramodular/WIP/_TaskRetryPolicy.swift rename to Sources/Merge/Intramodular/Rate-limiting & Retrying/_TaskRetryPolicy.swift diff --git a/Sources/Merge/Intramodular/WIP/_TokenBucketRateLimiter.swift b/Sources/Merge/Intramodular/Rate-limiting & Retrying/_TokenBucketRateLimiter.swift similarity index 98% rename from Sources/Merge/Intramodular/WIP/_TokenBucketRateLimiter.swift rename to Sources/Merge/Intramodular/Rate-limiting & Retrying/_TokenBucketRateLimiter.swift index cab16fd..a9729cc 100644 --- a/Sources/Merge/Intramodular/WIP/_TokenBucketRateLimiter.swift +++ b/Sources/Merge/Intramodular/Rate-limiting & Retrying/_TokenBucketRateLimiter.swift @@ -21,7 +21,7 @@ public actor _TokenBucketRateLimiter: Sendable { // queue as it does for synchronization. private let bucket: TokenBucket - private let pending = _DoublyLinkedList() // fast append, fast remove first + private let pending = _NaiveDoublyLinkedList() // fast append, fast remove first private var isExecutingPendingTasks = false typealias Work = () -> Bool diff --git a/Sources/Merge/Intramodular/Utilities/_DoublyLinkedList.swift b/Sources/Merge/Intramodular/Utilities/Collections/_NaiveDoublyLinkedList.swift similarity index 97% rename from Sources/Merge/Intramodular/Utilities/_DoublyLinkedList.swift rename to Sources/Merge/Intramodular/Utilities/Collections/_NaiveDoublyLinkedList.swift index 3a5f797..33b6a7e 100644 --- a/Sources/Merge/Intramodular/Utilities/_DoublyLinkedList.swift +++ b/Sources/Merge/Intramodular/Utilities/Collections/_NaiveDoublyLinkedList.swift @@ -6,7 +6,7 @@ import Combine import Swallow /// A doubly linked list. -public final class _DoublyLinkedList { +public final class _NaiveDoublyLinkedList { // first <-> node <-> ... <-> last private(set) var first: Node? private(set) var last: Node? diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/Lock/Lock.swift b/Sources/Merge/Intramodular/Utilities/Mutex/Lock/Lock.swift index fbe98f0..36ce2db 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/Lock/Lock.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/Lock/Lock.swift @@ -4,18 +4,18 @@ import Swallow -public protocol Lock: ScopedMutex, Sendable { +public protocol Lock: ScopedMutexProtocol, Sendable { func acquireOrBlock() func relinquish() } -public protocol TestableLock: Lock, TestableScopedMutex { +public protocol TestableLock: Lock, TestableScopedMutexProtocol { var hasBeenAcquired: Bool { get } func acquireOrFail() throws } -public protocol ReentrantLock: Lock, ReentrantMutex { +public protocol ReentrantLock: Lock, ReentrantMutexProtocol { } diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/Lock/ReadWriteLock.swift b/Sources/Merge/Intramodular/Utilities/Mutex/Lock/ReadWriteLockProtocol.swift similarity index 77% rename from Sources/Merge/Intramodular/Utilities/Mutex/Lock/ReadWriteLock.swift rename to Sources/Merge/Intramodular/Utilities/Mutex/Lock/ReadWriteLockProtocol.swift index ff93785..9473b62 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/Lock/ReadWriteLock.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/Lock/ReadWriteLockProtocol.swift @@ -4,7 +4,7 @@ import Swallow -protocol ReadWriteLock: Lock { +protocol ReadWriteLockProtocol: Lock { func acquireOrBlockForReading() func relinquishForReading() @@ -12,7 +12,7 @@ protocol ReadWriteLock: Lock { func relinquishForWriting() } -protocol ReentrantReadWriteLock: ReentrantLock { +protocol ReentrantReadWriteLockProtocol: ReentrantLock { func acquireOrBlockForReading() func relinquishForReading() diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/Mutex.swift b/Sources/Merge/Intramodular/Utilities/Mutex/Mutex.swift deleted file mode 100644 index 98a94e0..0000000 --- a/Sources/Merge/Intramodular/Utilities/Mutex/Mutex.swift +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) Vatsal Manot -// - -import Swallow - -public protocol Mutex: Sendable { - -} - -public protocol ReentrantMutex: Mutex { - -} diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtected.swift b/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtected.swift index 7db98ab..664f205 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtected.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtected.swift @@ -34,7 +34,7 @@ open class AnyMutexProtected { /// Notes: /// - `MutexProtected` checks whether its enclosing self is a `_MutexProtectedType` and if so, uses the enclosing self's mutex to protect the stored value. @propertyWrapper -public final class MutexProtected: AnyMutexProtected, @unchecked Sendable { +public final class MutexProtected: AnyMutexProtected, @unchecked Sendable { public private(set) var mutex: Mutex override public var wrappedValue: Value { diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtocol.swift b/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtocol.swift new file mode 100644 index 0000000..d6a6c39 --- /dev/null +++ b/Sources/Merge/Intramodular/Utilities/Mutex/MutexProtocol.swift @@ -0,0 +1,20 @@ +// +// Copyright (c) Vatsal Manot +// + +import Swallow + +public protocol MutexProtocol: Sendable { + +} + +public protocol ReentrantMutexProtocol: MutexProtocol { + +} + +// MARK: - Deprecated + +@available(*, deprecated, renamed: "MutexProtocol") +public typealias Mutex = MutexProtocol +@available(*, deprecated, renamed: "ReentrantMutexProtocol") +public typealias ReentrantMutex = ReentrantMutexProtocol diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/ScopedMutex.swift b/Sources/Merge/Intramodular/Utilities/Mutex/ScopedMutexProtocol.swift similarity index 88% rename from Sources/Merge/Intramodular/Utilities/Mutex/ScopedMutex.swift rename to Sources/Merge/Intramodular/Utilities/Mutex/ScopedMutexProtocol.swift index beeb59b..641cd2d 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/ScopedMutex.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/ScopedMutexProtocol.swift @@ -5,7 +5,7 @@ import Swallow /// A mutual exclusion device capable of scoping the execution of a function. -public protocol ScopedMutex: Mutex { +public protocol ScopedMutexProtocol: MutexProtocol { @discardableResult func withCriticalScope(_: (() throws -> T)) rethrows -> T @@ -16,26 +16,26 @@ public protocol ScopedMutex: Mutex { } /// An asynchronous mutual exclusion device capable of scoping the execution of a function. -public protocol AsyncScopedMutex { +public protocol AsyncScopedMutexProtocol { @discardableResult func withCriticalScope(_: (() async throws -> T)) async rethrows -> T } -public protocol ScopedReadWriteMutex: ScopedMutex { +public protocol ScopedReadWriteMutexProtocol: ScopedMutexProtocol { @discardableResult func withCriticalScopeForReading(_: (() throws -> T)) rethrows -> T @discardableResult func withCriticalScopeForWriting(_: (() throws -> T)) rethrows -> T } -public protocol TestableScopedMutex: ScopedMutex { +public protocol TestableScopedMutexProtocol: ScopedMutexProtocol { @discardableResult func attemptWithCriticalScope(_: (() throws -> T)) rethrows -> T? } // MARK: - Implementation -extension ScopedMutex { +extension ScopedMutexProtocol { @discardableResult public func _withCriticalScopeForReading(_ f: (() throws -> T)) rethrows -> T { return try withCriticalScope(f) @@ -47,7 +47,7 @@ extension ScopedMutex { } } -extension ScopedReadWriteMutex { +extension ScopedReadWriteMutexProtocol { @discardableResult public func withCriticalScope(_ f: (() throws -> T)) rethrows -> T { return try withCriticalScopeForWriting(f) @@ -66,7 +66,7 @@ extension ScopedReadWriteMutex { // MARK: - Extensions -extension ScopedMutex { +extension ScopedMutexProtocol { @discardableResult public func withCriticalScope(if predicate: @autoclosure () -> Bool, _ body: (() throws -> T)) rethrows -> T? { return try withCriticalScope { @@ -90,7 +90,7 @@ extension ScopedMutex { } } -extension ScopedReadWriteMutex { +extension ScopedReadWriteMutexProtocol { @discardableResult public func withCriticalScopeForReading(execute work: @autoclosure () throws -> T) rethrows -> T { return try withCriticalScopeForReading(work) diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/AnySemaphore.swift b/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/AnySemaphore.swift index 5422de5..e7bd57f 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/AnySemaphore.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/AnySemaphore.swift @@ -4,13 +4,15 @@ import Swallow -public final class AnySemaphore: Semaphore { +public final class AnySemaphore: SemaphoreProtocol { public let base: any Sendable private let signalImpl: @Sendable (Any) -> (() -> Any) private let waitImpl: @Sendable (Any) -> (() -> Any) - public init(_ semaphore: S) { + public init( + _ semaphore: S + ) { self.base = semaphore signalImpl = { S.signal($0 as! S) } diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/Semaphore.swift b/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/SemaphoreProtocol.swift similarity index 56% rename from Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/Semaphore.swift rename to Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/SemaphoreProtocol.swift index 04ae3bb..f589dbd 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/Semaphore.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/Semaphore/SemaphoreProtocol.swift @@ -4,7 +4,7 @@ import Swallow -public protocol Semaphore: Mutex { +public protocol SemaphoreProtocol: MutexProtocol { associatedtype WaitResult associatedtype SignalResult @@ -14,3 +14,8 @@ public protocol Semaphore: Mutex { @discardableResult func signal() -> SignalResult } + +// MARK: - Deprecated + +@available(*, deprecated, renamed: "SemaphoreProtocol") +public typealias Semaphore = SemaphoreProtocol diff --git a/Sources/Merge/Intramodular/Utilities/Mutex/_MutexProtectedType.swift b/Sources/Merge/Intramodular/Utilities/Mutex/_MutexProtectedType.swift index ffe6bac..66bf12d 100644 --- a/Sources/Merge/Intramodular/Utilities/Mutex/_MutexProtectedType.swift +++ b/Sources/Merge/Intramodular/Utilities/Mutex/_MutexProtectedType.swift @@ -9,49 +9,67 @@ import Swallow /// /// This type is a work-in-progress. Do not use this type directly in your code. public protocol _MutexProtectedType: Sendable { - associatedtype Mutex: Merge.Mutex + associatedtype Mutex: Merge.MutexProtocol var mutex: Mutex { get } } -extension _MutexProtectedType where Mutex: ScopedMutex { +extension _MutexProtectedType where Mutex: ScopedMutexProtocol { public typealias _MutexProtected = Merge.MutexProtected } // MARK: - Extensions -extension _MutexProtectedType where Mutex: ScopedMutex { +extension _MutexProtectedType where Mutex: ScopedMutexProtocol { @discardableResult - public func withMutexProtectedCriticalScope(_ body: (() throws -> T)) rethrows -> T { + public func withMutexProtectedCriticalScope( + _ body: ( + () throws -> T + ) + ) rethrows -> T { return try mutex.withCriticalScope(body) } @discardableResult - public func withMutexProtectedCriticalScope(if predicate: @autoclosure () -> Bool, _ body: (() throws -> T)) rethrows -> T? { + public func withMutexProtectedCriticalScope( + if predicate: @autoclosure () -> Bool, + _ body: (() throws -> T) + ) rethrows -> T? { return try mutex.withCriticalScope(if: predicate()) { return try body() } } @discardableResult - public func withMutexProtectedCriticalScope(unwrapping value: @autoclosure () -> T?, _ body: ((T) throws -> U)) rethrows -> U? { + public func withMutexProtectedCriticalScope( + unwrapping value: @autoclosure () -> T?, + _ body: ((T) throws -> U) + ) rethrows -> U? { return try mutex.withCriticalScope(unwrapping: value(), body) } } -extension _MutexProtectedType where Mutex: ScopedReadWriteMutex { +extension _MutexProtectedType where Mutex: ScopedReadWriteMutexProtocol { @discardableResult - public func withMutexProtectedCriticalScopeForReading(_ body: (() throws -> T)) rethrows -> T { + public func withMutexProtectedCriticalScopeForReading( + _ body: ( + () throws -> T + ) + ) rethrows -> T { return try mutex.withCriticalScopeForReading(body) } @discardableResult - public func withMutexProtectedCriticalScopeForReading(do expression: @autoclosure () throws -> T) rethrows -> T { + public func withMutexProtectedCriticalScopeForReading( + do expression: @autoclosure () throws -> T + ) rethrows -> T { return try mutex.withCriticalScopeForReading(expression) } @discardableResult - public func withMutexProtectedCriticalScopeForWriting(_ body: (() throws -> T)) rethrows -> T { + public func withMutexProtectedCriticalScopeForWriting( + _ body: (() throws -> T) + ) rethrows -> T { return try mutex.withCriticalScopeForWriting(body) } } diff --git a/Sources/Merge/Intramodular/Utilities/_SwiftTaskProtocol.swift b/Sources/Merge/Intramodular/Utilities/_SwiftTaskProtocol.swift index daf823e..ee9955e 100644 --- a/Sources/Merge/Intramodular/Utilities/_SwiftTaskProtocol.swift +++ b/Sources/Merge/Intramodular/Utilities/_SwiftTaskProtocol.swift @@ -2,8 +2,10 @@ // Copyright (c) Vatsal Manot // +import _Concurrency import Swift +/// A protocol for `_Concurrency.Task` to conform to. public protocol _SwiftTaskProtocol: Sendable { associatedtype Success associatedtype Failure diff --git a/Sources/Merge/Intramodular/WIP/_TaskSinkProtocol.swift b/Sources/Merge/Intramodular/WIP/_TaskSinkProtocol.swift index df7f620..f6a140b 100644 --- a/Sources/Merge/Intramodular/WIP/_TaskSinkProtocol.swift +++ b/Sources/Merge/Intramodular/WIP/_TaskSinkProtocol.swift @@ -6,12 +6,12 @@ import Combine import Swallow @_spi(Internal) -public protocol _TaskSinkProtocol<_TaskFailureType> { - associatedtype _TaskFailureType: Error +public protocol _TaskSinkProtocol<_ObservableTaskFailureType> { + associatedtype _ObservableTaskFailureType: Error associatedtype _ResultFailureType: Error func receive( - _ task: Task + _ task: Task ) async -> Result } @@ -20,14 +20,14 @@ extension _TaskSinkProtocol { @discardableResult func _opaque_receive( _ task: Task - ) async -> Result where _TaskFailureType == Never { + ) async -> Result where _ObservableTaskFailureType == Never { await self.receive(task).mapError({ $0 as Error }) } @discardableResult func _opaque_receive( _ task: Task - ) async -> Result where _TaskFailureType == Swift.Error { + ) async -> Result where _ObservableTaskFailureType == Swift.Error { await self.receive(task).mapError({ $0 as Error }) } } @@ -36,7 +36,7 @@ extension _TaskSinkProtocol { @_spi(Internal) extension TaskQueue: _TaskSinkProtocol { - public typealias _TaskFailureType = Never + public typealias _ObservableTaskFailureType = Never public typealias _ResultFailureType = CancellationError public func receive( @@ -50,7 +50,7 @@ extension TaskQueue: _TaskSinkProtocol { @_spi(Internal) extension ThrowingTaskQueue: _TaskSinkProtocol { - public typealias _TaskFailureType = Swift.Error + public typealias _ObservableTaskFailureType = Swift.Error public typealias _ResultFailureType = Swift.Error public func receive( diff --git a/Sources/Merge/module.swift b/Sources/Merge/module.swift index 0e5cc0a..aa50d08 100644 --- a/Sources/Merge/module.swift +++ b/Sources/Merge/module.swift @@ -8,3 +8,18 @@ @_exported import Swallow @_exported import SwallowMacrosClient @_exported import SwiftDI + +public enum _module { + +} + +// MARK: - Deprecated + +@available(*, deprecated, renamed: "ObservableTaskFailure") +public typealias TaskFailure = ObservableTaskFailure +@available(*, deprecated, renamed: "ObservableTaskStatusType") +public typealias TaskStatusType = ObservableTaskStatusType +@available(*, deprecated, renamed: "ObservableTaskStatus") +public typealias TaskStatus = ObservableTaskStatus +@available(*, deprecated, renamed: "ObservableTaskStatusDescription") +public typealias TaskStatusDescription = ObservableTaskStatusDescription