Skip to content
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
79 changes: 79 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/Dripper.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Dripper"
BuildableName = "Dripper"
BlueprintName = "Dripper"
ReferencedContainer = "container:">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DripperTests"
BuildableName = "DripperTests"
BlueprintName = "DripperTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "Dripper"
BuildableName = "Dripper"
BlueprintName = "Dripper"
ReferencedContainer = "container:">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
54 changes: 54 additions & 0 deletions .swiftpm/xcode/xcshareddata/xcschemes/DripperTests.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1600"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "DripperTests"
BuildableName = "DripperTests"
BlueprintName = "DripperTests"
ReferencedContainer = "container:">
</BuildableReference>
</TestableReference>
</Testables>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
43 changes: 30 additions & 13 deletions Examples/Counter/Counter/Counter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,40 @@ struct Counter: Dripper {

@Observable
@MainActor
final class State: Sendable {
final class State: @preconcurrency CustomStringConvertible {

// MARK: Properties

var counter: Int = .zero
var text = ""

@ObservationIgnored private let id: UUID

// MARK: Computed Properties

var description: String {
"Count: \(counter)"
}

// MARK: Lifecycle

init(counter: Int = .zero, text: String = "") {
let id = UUID()
self.id = id
self.counter = counter
self.text = text
os_log("State initialized: \(id)")
}

deinit {
os_log("State deinitialized: \(self.id)")
}
}

enum Action {
case increaseCounter
case decreaseCounter
case setCounter(value: Int)
case resetCounter
case randomNumber
}
Expand All @@ -39,14 +65,14 @@ struct Counter: Dripper {
state.counter += 1
case .decreaseCounter:
state.counter -= 1
case .setCounter(let value):
state.counter = value
case .resetCounter:
state.counter = .zero
case .randomNumber:
return .run { pour in
let randomNumber = try await randomNumber()

pour(.decreaseCounter)
state.counter = randomNumber
pour(.setCounter(value: randomNumber))
}
}

Expand Down Expand Up @@ -129,12 +155,3 @@ struct CounterView: View {
}
)
}

#Preview {
CounterView(
station: Station(
initialState: Counter.State(),
dripper: Counter()
)
)
}
25 changes: 21 additions & 4 deletions Examples/Counter/Counter/CounterApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,30 @@ import Dripper

@main
struct CounterApp: App {
private let counterStation = Station(initialState: Counter.State()) {
Counter()
}

// MARK: Properties

@State private var path: [Int] = []

// MARK: Computed Properties

var body: some Scene {
WindowGroup {
CounterView(station: counterStation)
NavigationStack(path: $path) {
List {
NavigationLink("1", value: 1)
NavigationLink("2", value: 2)
NavigationLink("3", value: 3)
}
.navigationTitle("Starting Counter")
.navigationDestination(for: Int.self) { number in
CounterView(
station: Station(initialState: Counter.State(counter: number)) {
Counter()
}
)
}
}
}
}
}
15 changes: 7 additions & 8 deletions Sources/Dripper/Drip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,28 @@

import Foundation

public struct Drip<State: ObservableState, Action>: Dripper {

// MARK: Nested Types

public typealias Dripping = @MainActor (_ state: State, _ action: Action) -> Effect<Action>?
public struct Drip<State: StationState, Action>: Dripper {

// MARK: Properties

@usableFromInline let drip: Dripping
@usableFromInline let drip: @MainActor (State, Action) -> Effect<Action>?

// MARK: Lifecycle

@inlinable
public init(_ drip: @escaping Dripping) {
public init(
_ drip: @MainActor @escaping (_ state: State, _ action: Action) -> Effect<Action>
) {
self.init(internal: drip)
}

@inlinable
public init(_ dripper: some Dripper<State, Action>) {
self.init(internal: dripper.drip)
}

@usableFromInline
init(internal drip: @escaping Dripping) {
init(internal drip: @MainActor @escaping (State, Action) -> Effect<Action>?) {
self.drip = drip
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/Dripper/Dripper.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public typealias DripperOf<D: Dripper> = Dripper<D.State, D.Action>

@MainActor
public protocol Dripper<State, Action>: Sendable {
associatedtype State: ObservableState
associatedtype State: StationState
associatedtype Action
associatedtype Body

Expand Down
4 changes: 2 additions & 2 deletions Sources/Dripper/DripperBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import Foundation

@resultBuilder
public enum DripperBuilder<State: ObservableState, Action> {
public enum DripperBuilder<State: StationState, Action> {
@inlinable
public static func buildBlock<D: Dripper<State, Action>>(_ dripper: D) -> D {
dripper
Expand All @@ -19,8 +19,8 @@ public enum DripperBuilder<State: ObservableState, Action> {
expression
}

@inlinable
@MainActor
@inlinable
public static func buildExpression(
_ expression: any Dripper<State, Action>
) -> Drip<State, Action> {
Expand Down
16 changes: 6 additions & 10 deletions Sources/Dripper/Effect.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,21 @@ import OSLog

// MARK: - Effect

public struct Effect<Action> {
public typealias Blend = (_ blend: Pour<Action>) async -> Void

@usableFromInline let blend: Blend
public struct Effect<Action>: Sendable {
@usableFromInline let blend: @Sendable (_ pour: Pour<Action>) async -> Void

@usableFromInline
init(blend: @escaping Blend) {
init(blend: @Sendable @escaping (_ pour: Pour<Action>) async -> Void) {
self.blend = blend
}
}

// MARK: - Pour

@MainActor
public struct Pour<Action>: Sendable {
let pour: @MainActor @Sendable (Action) -> Void
let pour: @Sendable (Action) -> Void

@usableFromInline
init(pour: @escaping @MainActor @Sendable (Action) -> Void) {
public init(pour: @Sendable @escaping (Action) -> Void) {
self.pour = pour
}

Expand All @@ -50,7 +46,7 @@ extension Effect {
// MARK: Static Functions

public static func run(
blend: @escaping @MainActor (_ pour: Pour<Action>) async throws -> Void,
blend: @MainActor @escaping (_ pour: Pour<Action>) async throws -> Void,
catch errorHandler: (@MainActor (_ error: any Error, _ pour: Pour<Action>) async -> Void)? = nil,
fileID: StaticString = #fileID,
line: UInt = #line
Expand Down
Loading