Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
muukii committed Sep 16, 2024
1 parent f739e65 commit d452fac
Show file tree
Hide file tree
Showing 13 changed files with 122 additions and 95 deletions.
11 changes: 6 additions & 5 deletions Package.resolved
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"originHash" : "82f71c92629a240db65e931912dfb2240dd0b70609e84bc12a7b6ccab081b14b",
"pins" : [
{
"identity" : "rxswift",
Expand Down Expand Up @@ -59,19 +60,19 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-syntax.git",
"state" : {
"revision" : "64889f0c732f210a935a0ad7cda38f77f876262d",
"version" : "509.1.1"
"revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82",
"version" : "510.0.3"
}
},
{
"identity" : "viewinspector",
"kind" : "remoteSourceControl",
"location" : "https://github.com/nalexn/ViewInspector.git",
"state" : {
"revision" : "7b1732802ffe30e6a67754bda6c7819e5cb0eb70",
"version" : "0.9.11"
"branch" : "0.10.0",
"revision" : "23d6fabc6e8f0115c94ad3af5935300c70e0b7fa"
}
}
],
"version" : 2
"version" : 3
}
20 changes: 11 additions & 9 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// swift-tools-version:6.0
import PackageDescription
// swift-tools-version: 6.0
import CompilerPluginSupport
import PackageDescription

let package = Package(
name: "Verge",
Expand Down Expand Up @@ -28,7 +28,7 @@ let package = Package(
/// for testing
.package(url: "https://github.com/nalexn/ViewInspector.git", branch: "0.10.0"),
.package(url: "https://github.com/apple/swift-syntax.git", from: "510.0.3"),
.package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.2.1")
.package(url: "https://github.com/pointfreeco/swift-macro-testing.git", from: "0.2.1"),
],
targets: [

Expand All @@ -37,7 +37,7 @@ let package = Package(
name: "VergeMacrosPlugin",
dependencies: [
.product(name: "SwiftSyntaxMacros", package: "swift-syntax"),
.product(name: "SwiftCompilerPlugin", package: "swift-syntax")
.product(name: "SwiftCompilerPlugin", package: "swift-syntax"),
]
),

Expand Down Expand Up @@ -115,11 +115,13 @@ let package = Package(
name: "VergeTinyTests",
dependencies: ["VergeTiny"]
),
.testTarget(name: "VergeMacrosTests", dependencies: [
"VergeMacrosPlugin",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
.product(name: "MacroTesting", package: "swift-macro-testing"),
])
.testTarget(
name: "VergeMacrosTests",
dependencies: [
"VergeMacrosPlugin",
.product(name: "SwiftSyntaxMacrosTestSupport", package: "swift-syntax"),
.product(name: "MacroTesting", package: "swift-macro-testing"),
]),
],
swiftLanguageModes: [.v5, .v6]
)
6 changes: 3 additions & 3 deletions Sources/Verge/Derived/Derived+Assign.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ extension StoreDriverType {
*/
public func assign(
queue: some TargetQueueType = .passthrough,
to binder: @escaping (Changes<TargetStore.State>) -> Void
to binder: @escaping @Sendable (Changes<TargetStore.State>) -> Void
) -> StoreStateSubscription {
store.asStore().sinkState(queue: queue, receive: binder)
}
Expand All @@ -39,8 +39,8 @@ extension StoreDriverType {
- Returns: a cancellable. See detail of handling cancellable from ``StoreSubscription``'s docs
*/
public func assign(
queue: MainActorTargetQueue,
to binder: @escaping (Changes<TargetStore.State>) -> Void
queue: some MainActorTargetQueueType,
to binder: @escaping @MainActor (Changes<TargetStore.State>) -> Void
) -> StoreStateSubscription {
store.asStore().sinkState(queue: queue, receive: binder)
}
Expand Down
10 changes: 5 additions & 5 deletions Sources/Verge/Derived/Derived.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public class Derived<Value: Equatable>: Store<Value, Never>, DerivedType, @unche
get pipeline: Pipeline,
set: ((Value) -> Void)?,
initialUpstreamState: UpstreamState,
subscribeUpstreamState: (@escaping (UpstreamState) -> Void) -> any Cancellable,
subscribeUpstreamState: (@escaping @Sendable (UpstreamState) -> Void) -> any Cancellable,
retainsUpstream: Any?
) where Pipeline.Input == UpstreamState, Value == Pipeline.Output {

Expand Down Expand Up @@ -173,7 +173,7 @@ public class Derived<Value: Equatable>: Store<Value, Never>, DerivedType, @unche
private func _combined_sinkValue(
dropsFirst: Bool = false,
queue: some TargetQueueType,
receive: @escaping (Changes<Value>) -> Void
receive: @escaping @Sendable (Changes<Value>) -> Void
) -> StoreStateSubscription {
_primitive_sinkState(
dropsFirst: dropsFirst,
Expand Down Expand Up @@ -226,7 +226,7 @@ extension Derived where Value : Equatable {
public func sinkChangedPrimitiveValue(
dropsFirst: Bool = false,
queue: some TargetQueueType,
receive: @escaping (Value) -> Void
receive: @escaping @Sendable (Value) -> Void
) -> StoreStateSubscription {
sinkState(dropsFirst: dropsFirst, queue: queue) { (changes) in
changes.ifChanged().do { value in
Expand All @@ -242,7 +242,7 @@ extension Derived where Value : Equatable {
/// - Returns: A subscriber that performs the provided closure upon receiving values.
public func sinkChangedPrimitiveValue(
dropsFirst: Bool = false,
queue: MainActorTargetQueue = .mainIsolated(),
queue: some MainActorTargetQueueType = .mainIsolated(),
receive: @escaping @MainActor (Value) -> Void
) -> StoreStateSubscription {
sinkState(dropsFirst: dropsFirst, queue: queue) { @MainActor changes in
Expand Down Expand Up @@ -407,7 +407,7 @@ extension Derived where Value == Never {
In most cases, `Store` will be running underlying.
*/
@propertyWrapper
public final class BindingDerived<Value: Equatable>: Derived<Value> {
public final class BindingDerived<Value: Equatable>: Derived<Value>, @unchecked Sendable {

/**
Returns a derived value that created by get-pipeline.
Expand Down
1 change: 1 addition & 0 deletions Sources/Verge/Library/Signpost.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import Foundation

nonisolated(unsafe)
public var _verge_signpost_enabled = ProcessInfo.processInfo.environment["VERGE_SIGNPOST_ENABLED"] != nil

@usableFromInline
Expand Down
2 changes: 1 addition & 1 deletion Sources/Verge/Library/VergeAnyCancellable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public final class VergeAnyCancellable: Hashable, Cancellable, @unchecked Sendab
public init() {
}

public convenience init(onDeinit: @escaping @Sendable () -> Void) {
public convenience init(onDeinit: @escaping () -> Void) {
self.init()
self.actions = [onDeinit]
}
Expand Down
4 changes: 2 additions & 2 deletions Sources/Verge/Library/VergeConcurrency.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,11 @@ import Foundation

public enum VergeConcurrency {

public final class RecursiveLock: NSRecursiveLock {
public final class RecursiveLock: NSRecursiveLock, @unchecked Sendable {

}

public struct UnfairLock: ~Copyable {
public struct UnfairLock: ~Copyable, @unchecked Sendable {
private let _lock: os_unfair_lock_t

public init() {
Expand Down
4 changes: 2 additions & 2 deletions Sources/Verge/Logging/RuntimeSanitizer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,14 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

public final class RuntimeSanitizer {
public struct RuntimeSanitizer: Sendable {

public static let global = RuntimeSanitizer()

public var isSanitizerStateReceivingByCorrectOrder: Bool = false
public var isRecursivelyCommitDetectionEnabled: Bool = false

public var onDidFindRuntimeError: (RuntimeError) -> Void = { _ in }
public var onDidFindRuntimeError: @Sendable (RuntimeError) -> Void = { _ in }

public init() {

Expand Down
101 changes: 54 additions & 47 deletions Sources/Verge/Store/AnyTargetQueue.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,73 +23,80 @@ import Foundation
import Atomics

public protocol TargetQueueType {
func execute(_ workItem: @escaping () -> Void)
func execute(_ workItem: sending @escaping @Sendable () -> Void)
}

/// Describes queue to dispatch event
/// Currently light-weight impl
/// A reason why class is to take an object identifier.
public final class AnyTargetQueue: TargetQueueType {

private let _execute: (@escaping () -> Void) -> Void
private let _execute: (@escaping @Sendable () -> Void) -> Void

fileprivate init(
_execute: @escaping (@escaping () -> Void) -> Void
_execute: @escaping (@escaping @Sendable () -> Void) -> Void
) {
self._execute = _execute
}

public func execute(_ workItem: @escaping () -> Void) {
public func execute(_ workItem: @escaping @Sendable () -> Void) {
_execute(workItem)
}

}

public final class MainActorTargetQueue {
public protocol MainActorTargetQueueType {
func execute(_ workItem: @escaping @MainActor () -> Void)
}

public static let sharedImmediacy = MainActorTargetQueue(mode: .immediacy)
extension MainActorTargetQueueType where Self == ImmediateMainActorTargetQueue {
public static func mainIsolated() -> Self {
.init()
}
}

public enum Mode {
/// Always execuses work item with dispatch(hop) to main queue.
case alwaysDispatch
public final class MainActorTargetQueue: MainActorTargetQueueType {

/// Execuses work item immediately if receives it on main context and main queue is empty.
case immediacy
init() {
}

public let mode: Mode
private let numberEnqueued = ManagedAtomic<UInt64>.init(0)

init(mode: Mode) {
self.mode = mode
public func execute(_ workItem: @escaping @MainActor () -> Void) {

DispatchQueue.main.async {
workItem()
}
}

public func execute(_ workItem: @escaping () -> Void) {
}

public struct ImmediateMainActorTargetQueue: Sendable, MainActorTargetQueueType {

public static let shared = Self()

switch mode {
case .alwaysDispatch:
private let numberEnqueued = ManagedAtomic<UInt64>.init(0)

init() {

DispatchQueue.main.async {
}

public func execute(_ workItem: @escaping @MainActor () -> Void) {

let previousNumberEnqueued = numberEnqueued.loadThenWrappingIncrement(ordering: .sequentiallyConsistent)

if Thread.isMainThread && previousNumberEnqueued == 0 {
MainActor.assumeIsolated {
workItem()
}

case .immediacy:

let previousNumberEnqueued = numberEnqueued.loadThenWrappingIncrement(ordering: .sequentiallyConsistent)

if Thread.isMainThread && previousNumberEnqueued == 0 {
numberEnqueued.wrappingDecrement(ordering: .sequentiallyConsistent)
} else {
DispatchQueue.main.async {
workItem()
numberEnqueued.wrappingDecrement(ordering: .sequentiallyConsistent)
} else {
DispatchQueue.main.async {
workItem()
self.numberEnqueued.wrappingDecrement(ordering: .sequentiallyConsistent)
}
self.numberEnqueued.wrappingDecrement(ordering: .sequentiallyConsistent)
}

}

}

}

private enum StaticMember {
Expand Down Expand Up @@ -164,40 +171,40 @@ extension MainActorTargetQueue {

/// It dispatches to main-queue asynchronously always.
public static var asyncMain: MainActorTargetQueue {
MainActorTargetQueue.init(mode: .alwaysDispatch)
return .init()
}

/// It dispatches to main-queue as possible as synchronously. Otherwise, it dispatches asynchronously from other background-thread.
public static var main: MainActorTargetQueue {
MainActorTargetQueue.sharedImmediacy
public static var main: ImmediateMainActorTargetQueue {
return .shared
}

/// It dispatches to main-queue as possible as synchronously. Otherwise, it dispatches asynchronously from other background-thread.
/// This create isolated queue against using `.main`.
public static func mainIsolated() -> MainActorTargetQueue {
return .init(mode: .immediacy)
public static func mainIsolated() -> ImmediateMainActorTargetQueue {
return .init()
}
}

public enum Queues {

struct MainActor: TargetQueueType {
struct MainActor<Underlying: MainActorTargetQueueType>: TargetQueueType {

let underlying: MainActorTargetQueue
let underlying: Underlying

init(_ underlying: MainActorTargetQueue) {
init(_ underlying: Underlying) {
self.underlying = underlying
}

public func execute(_ workItem: @escaping () -> Void) {
public func execute(_ workItem: sending @escaping @Sendable () -> Void) {
underlying.execute(workItem)
}

}

public struct Passthrough: TargetQueueType {

public func execute(_ workItem: @escaping () -> Void) {
public func execute(_ workItem: sending @escaping @Sendable () -> Void) {
workItem()
}

Expand All @@ -207,7 +214,7 @@ public enum Queues {

private let executor: BackgroundActor = .init()

public func execute(_ workItem: @escaping () -> Void) {
public func execute(_ workItem: sending @escaping @Sendable () -> Void) {
Task {
await executor.perform {
workItem()
Expand All @@ -221,10 +228,10 @@ public enum Queues {

}

func perform<R>(_ operation: () throws -> R) rethrows -> R {
func perform<R>(_ operation: sending @Sendable () throws -> R) rethrows -> R {
try operation()
}

}

}
Expand Down
6 changes: 3 additions & 3 deletions Sources/Verge/Store/Pipeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ extension ContinuousResult: Equatable where Output: Equatable {
/**
A filter object that yields the output produced from the input.
*/
public protocol PipelineType<Input, Output> {
public protocol PipelineType<Input, Output>: Sendable {

associatedtype Input
associatedtype Output
Expand All @@ -59,10 +59,10 @@ public enum Pipelines {

public typealias Input = Changes<Source>

public let selector: (borrowing Input.Value) -> Output
public let selector: @Sendable (borrowing Input.Value) -> Output

public init(
selector: @escaping (borrowing Input.Value) -> Output
selector: @escaping @Sendable (borrowing Input.Value) -> Output
) {
self.selector = selector
}
Expand Down
Loading

0 comments on commit d452fac

Please sign in to comment.