Skip to content

Commit

Permalink
Update MainActorStore (#453)
Browse files Browse the repository at this point in the history
  • Loading branch information
muukii authored Nov 16, 2023
1 parent fb298e4 commit 6bd0295
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 2 deletions.
116 changes: 116 additions & 0 deletions Sources/Verge/Store/IsolatedStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,24 @@ public final class MainActorStore<State: StateType, Activity>: DerivedMaking, Se
backingStore._send(activity: activity, trace: trace)
}

public func sinkActivity(
queue: MainActorTargetQueue = .mainIsolated(),
receive: @escaping @MainActor (Activity) -> Void
) -> StoreSubscription {
backingStore.sinkActivity(queue: queue, receive: receive)
}

/// Subscribe the activity
///
/// - Returns: A subscriber that performs the provided closure upon receiving values.
@_disfavoredOverload
public func sinkActivity(
queue: some TargetQueueType,
receive: @escaping (Activity) -> Void
) -> StoreSubscription {
backingStore.sinkActivity(queue: queue, receive: receive)
}

/**
Subscribe the state that scoped

Expand Down Expand Up @@ -94,6 +112,44 @@ public final class MainActorStore<State: StateType, Activity>: DerivedMaking, Se
.sinkState(dropsFirst: dropsFirst, queue: queue, receive: receive)
}

/// Subscribe the state changes
///
/// First object always returns true from ifChanged / hasChanges / noChanges unless dropsFirst is true.
///
/// - Parameters:
/// - scan: Accumulates a specified type of value over receiving updates.
/// - dropsFirst: Drops the latest value on started. if true, receive closure will call from next state updated.
/// - queue: Specify a queue to receive changes object.
/// - Returns: A subscriber that performs the provided closure upon receiving values.
@_disfavoredOverload
public func sinkState<Accumulate>(
scan: Scan<Changes<State>, Accumulate>,
dropsFirst: Bool = false,
queue: some TargetQueueType,
receive: @escaping (Changes<State>, Accumulate) -> Void
) -> StoreSubscription {
backingStore.sinkState(scan: scan, dropsFirst: dropsFirst, queue: queue, receive: receive)
}

/// Subscribe the state changes
///
/// First object always returns true from ifChanged / hasChanges / noChanges unless dropsFirst is true.
///
/// - Parameters:
/// - scan: Accumulates a specified type of value over receiving updates.
/// - dropsFirst: Drops the latest value on started. if true, receive closure will call from next state updated.
/// - queue: Specify a queue to receive changes object.
/// - Returns: A subscriber that performs the provided closure upon receiving values.
@discardableResult
public func sinkState<Accumulate>(
scan: Scan<Changes<State>, Accumulate>,
dropsFirst: Bool = false,
queue: MainActorTargetQueue = .mainIsolated(),
receive: @escaping @MainActor (Changes<State>, Accumulate) -> Void
) -> StoreSubscription {
backingStore.sinkState(scan: scan, dropsFirst: dropsFirst, queue: queue, receive: receive)
}

public nonisolated func derived<Pipeline: PipelineType>(
_ pipeline: Pipeline,
queue: some TargetQueueType = .passthrough
Expand Down Expand Up @@ -400,6 +456,24 @@ extension MainActorStoreDriverType {

}

public func sinkActivity(
queue: MainActorTargetQueue = .mainIsolated(),
receive: @escaping @MainActor (Activity) -> Void
) -> StoreSubscription {
store.sinkActivity(queue: queue, receive: receive)
}

/// Subscribe the activity
///
/// - Returns: A subscriber that performs the provided closure upon receiving values.
@_disfavoredOverload
public func sinkActivity(
queue: some TargetQueueType,
receive: @escaping (Activity) -> Void
) -> StoreSubscription {
store.sinkActivity(queue: queue, receive: receive)
}

/**
Subscribe the state that scoped

Expand Down Expand Up @@ -441,6 +515,48 @@ extension MainActorStoreDriverType {
})
}

/// Subscribe the state changes
///
/// First object always returns true from ifChanged / hasChanges / noChanges unless dropsFirst is true.
///
/// - Parameters:
/// - scan: Accumulates a specified type of value over receiving updates.
/// - dropsFirst: Drops the latest value on started. if true, receive closure will call from next state updated.
/// - queue: Specify a queue to receive changes object.
/// - Returns: A subscriber that performs the provided closure upon receiving values.
@_disfavoredOverload
public func sinkState<Accumulate>(
scan: Scan<Changes<State>, Accumulate>,
dropsFirst: Bool = false,
queue: some TargetQueueType,
receive: @escaping (Changes<Scope>, Accumulate) -> Void
) -> StoreSubscription {
return store.sinkState(scan: scan, dropsFirst: dropsFirst, queue: queue, receive: { state, scan in
receive(state.map({ $0[keyPath: scope] }), scan)
})
}

/// Subscribe the state changes
///
/// First object always returns true from ifChanged / hasChanges / noChanges unless dropsFirst is true.
///
/// - Parameters:
/// - scan: Accumulates a specified type of value over receiving updates.
/// - dropsFirst: Drops the latest value on started. if true, receive closure will call from next state updated.
/// - queue: Specify a queue to receive changes object.
/// - Returns: A subscriber that performs the provided closure upon receiving values.
@discardableResult
public func sinkState<Accumulate>(
scan: Scan<Changes<State>, Accumulate>,
dropsFirst: Bool = false,
queue: MainActorTargetQueue = .mainIsolated(),
receive: @escaping @MainActor (Changes<Scope>, Accumulate) -> Void
) -> StoreSubscription {
return store.sinkState(scan: scan, dropsFirst: dropsFirst, queue: queue, receive: { state, scan in
receive(state.map({ $0[keyPath: scope] }), scan)
})
}

public nonisolated func derived<Pipeline: PipelineType>(
_ pipeline: Pipeline,
queue: some TargetQueueType = .passthrough
Expand Down
44 changes: 43 additions & 1 deletion Sources/Verge/SwiftUI/StoreReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,48 @@ public struct StoreReader<StateType: Equatable, Content: View>: View {

}

public init<Activity>(
debug: Bool = false,
_ store: MainActorStore<StateType, Activity>,
@ViewBuilder content: @escaping @MainActor (inout StoreReaderComponents<StateType>.StateProxy) -> Content
) {

self.init(
identifier: ObjectIdentifier(store),
node: {
return .init(
store: store.backingStore,
retainValues: [store],
debug: debug
)
},
content: content
)

}

public init<Driver: MainActorStoreDriverType>(
debug: Bool = false,
_ storeDriver: Driver,
@ViewBuilder content: @escaping @MainActor (inout StoreReaderComponents<StateType>.StateProxy) -> Content
) where StateType == Driver.State {

let mainActorStore = storeDriver.store

self.init(
identifier: ObjectIdentifier(mainActorStore),
node: {
return .init(
store: mainActorStore.backingStore,
retainValues: [],
debug: debug
)
},
content: content
)

}

}

@available(iOS 14, *)
Expand Down Expand Up @@ -215,7 +257,7 @@ public enum StoreReaderComponents<StateType: Equatable> {
private let debug: Bool

private weak var source: (any DispatcherType<StateType>)?

init(
store: some DispatcherType<StateType>,
retainValues: [AnyObject],
Expand Down
3 changes: 3 additions & 0 deletions Sources/VergeMacrosPlugin/NormalizedStorageMacro.swift
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ extension NormalizedStorageMacro: ExtensionMacro {
extension \(structDecl.name.trimmed): NormalizedStorageType {}
""" as DeclSyntax).cast(ExtensionDeclSyntax.self),
("""
extension \(structDecl.name.trimmed): Sendable {}
""" as DeclSyntax).cast(ExtensionDeclSyntax.self),
("""
extension \(structDecl.name.trimmed): Equatable {}
""" as DeclSyntax).cast(ExtensionDeclSyntax.self),
("""
Expand Down
2 changes: 1 addition & 1 deletion Sources/VergeNormalization/VergeNormalization+Macros.swift
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

//@attached(member, names: arbitrary)
//@attached(memberAttribute)
@attached(extension, conformances: NormalizedStorageType, Equatable, names: named(Context), named(BBB), arbitrary)
@attached(extension, conformances: NormalizedStorageType, Equatable, Sendable, names: named(Context), named(BBB), arbitrary)
public macro NormalizedStorage() = #externalMacro(module: "VergeMacrosPlugin", type: "NormalizedStorageMacro")

@attached(peer)
Expand Down

0 comments on commit 6bd0295

Please sign in to comment.