Skip to content

Commit 5f243d3

Browse files
authored
Merge pull request #11 from sideeffect-io/feature/rename-asyncStateMachine
project: rename AsyncStateMachineSequence to AsyncStateMachine
2 parents c9aacdd + 004bc1d commit 5f243d3

10 files changed

Lines changed: 75 additions & 61 deletions

File tree

README.md

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -150,10 +150,10 @@ let runtime = Runtime<State, Event, Output>()
150150
.register(middleware: { (event: Event) in print("Event: \(event)") })
151151
```
152152

153-
The `AsyncStateMachineSequence` can then be instantiated:
153+
The `AsyncStateMachine` can then be instantiated:
154154

155155
```swift
156-
let sequence = AsyncStateMachineSequence(
156+
let sequence = AsyncStateMachine(
157157
stateMachine: stateMachine,
158158
runtime: runtime
159159
)
@@ -176,12 +176,12 @@ await sequence.send(Event.personsHaveEntered(persons: 3))
176176

177177
- Side effects are `async` functions executed in the context of `Tasks`.
178178
- Task priority can be set in the Runtime: `.map(output: Output.close(speed:), to: close(speed:), priority: .high)`.
179-
- Collaborative task cancellation applies: when an AsyncStateMachineSequence is deinit, all the pending side effect tasks will be marked as cancelled.
179+
- Collaborative task cancellation applies: when an `AsyncStateMachine` is deinit, all the pending side effect tasks will be marked as cancelled.
180180

181181
### Async sequence
182182

183-
- `AsyncStateMachineSequence` benefits from all the operators associated to `AsyncSequence` (`map`, `filter`, …). (See also [swift async algorithms](https://github.com/apple/swift-async-algorithms))
184-
- `AsyncStateMachineSequence` is compliant with a multiple producer / multiple consumer mode in a concurrent mode. Although to output is not shared (meaning each consumer will receive the successive versions of the state), the transitions are guaranteed concurrent-safe.
183+
- `AsyncStateMachine` benefits from all the operators associated to `AsyncSequence` (`map`, `filter`, …). (See also [swift async algorithms](https://github.com/apple/swift-async-algorithms))
184+
- `AsyncStateMachine` is compliant with a multiple producer / multiple consumer mode in a concurrent mode. Although to output is not shared (meaning each consumer will receive the successive versions of the state), the transitions are guaranteed concurrent-safe.
185185

186186
## How to inject dependencies?
187187

@@ -265,53 +265,53 @@ XCTStateMachine(stateMachine)
265265

266266
## Using Async State Machine with SwiftUI and UIKit
267267

268-
No matter the UI framework you use, rendering a user interface is about interpreting a state. You can use an `AsyncStateMachineSequence` as a reliable state factory, exposing the state with the provided `ViewState`.
268+
No matter the UI framework you use, rendering a user interface is about interpreting a state. You can use an `AsyncStateMachine` as a reliable state factory. `ViewStateMachine` is a handy wrapper around `AsyncStateMachine` that eases the consumption of the state from a UI perspective.
269269

270270
A simple and naive SwiftUI usage could be:
271271

272272
```swift
273273
struct ContentView: View {
274-
@ObservedObject viewState: ViewState<State, Event, Output>
274+
@ObservedObject viewStateMachine: ViewStateMachine<State, Event, Output>
275275

276276
var body: some View {
277277
VStack {
278-
Text(self.viewState.state.description)
278+
Text(self.viewStateMachine.state.description)
279279
Button {
280-
self.viewState.send(Event.personsHaveEntered(persons: 1))
280+
self.viewStateMachine.send(Event.personsHaveEntered(persons: 1))
281281
} label: {
282282
Text("New person")
283283
}
284284
Button {
285-
self.viewState.send(Event.closeButtonWasPressed)
285+
self.viewStateMachine.send(Event.closeButtonWasPressed)
286286
} label: {
287287
Text("Close the door")
288288
}
289289
}.task {
290-
await viewState.start()
290+
await self.viewStateMachine.start()
291291
}
292292
}
293293
}
294294

295295
296296

297-
let viewState = ViewState(myAsyncStateMachine)
298-
ContentView(viewState: viewState)
297+
let viewStateMachine = ViewStateMachine(asyncStateMachine: myAsyncStateMachine)
298+
ContentView(viewStateMachine: viewStateMachine)
299299
```
300300

301301
With UIKit, a simple and naive approach would be:
302302

303303
```swift
304304
let task: Task<Void, Never>!
305-
let viewState: ViewState<State, Event, Output>!
305+
let viewStateMachine: ViewStateMachine<State, Event, Output>!
306306
let cancellable = AnyCancellable()
307307

308308
override func viewDidLoad() {
309309
super.viewDidLoad()
310310
self.task = Task { [weak self] in
311-
await self?.viewState.start()
311+
await self?.viewStateMachine.start()
312312
}
313313

314-
self.cancellable = self.viewState.$state.sink { [weak self] state in
314+
self.cancellable = self.viewStateMachine.$state.sink { [weak self] state in
315315
self?.render(state: state)
316316
}
317317
}
@@ -332,7 +332,7 @@ func deinit() {
332332
Allows to send an event while awaiting for a specific state or set of states to resume.
333333

334334
```swift
335-
await viewState.send(
335+
await viewStateMachine.send(
336336
.closeButtonWasPressed,
337337
resumeWhen: .closed
338338
)`
@@ -372,13 +372,13 @@ When(states: OneOf {
372372
Allows to create a SwiftUI binding on the current state, sending an Event when the binding changes.
373373

374374
```swift
375-
self.viewState.binding(send: .closeButtonWasPressed)
375+
self.viewStateMachine.binding(send: .closeButtonWasPressed)
376376
```
377377

378378
Allows to create a SwiftUI binding on a property of the current state, sending an Event when the binding changes.
379379

380380
```swift
381-
self.viewState.binding(keypath: \.persons, send: .closeButtonWasPressed)
381+
self.viewStateMachine.binding(keypath: \.persons, send: .closeButtonWasPressed)
382382
```
383383

384384
### Connecting two state machines

Sample/Sample/ContentView.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ struct ContentView: View {
2626

2727
struct ContentView_Previews: PreviewProvider {
2828
static let viewStateMachine = ViewStateMachine(
29-
asyncStateMachineSequence: asyncSequence
29+
asyncStateMachine: asyncStateMachine
3030
)
3131

3232
static var previews: some View {

Sample/Sample/SampleApp.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import SwiftUI
1010

1111
@main
1212
struct SampleApp: App {
13-
let viewStateMachine = ViewStateMachine(asyncStateMachineSequence: asyncSequence)
13+
let viewStateMachine = ViewStateMachine(asyncStateMachine: asyncStateMachine)
1414

1515
var body: some Scene {
1616
WindowGroup {

Sample/Sample/StateMachine.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ actor Counter {
9696
}
9797

9898

99-
let asyncSequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
99+
let asyncStateMachine = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
100100

101101
extension Date {
102102
func getFormattedDate(format: String) -> String {

Sources/AsyncStateMachineSequence.swift renamed to Sources/AsyncStateMachine/AsyncStateMachine.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,11 @@
1-
public final class AsyncStateMachineSequence<S, E, O>: AsyncSequence, Sendable
1+
//
2+
// AsyncStateMachine.swift
3+
//
4+
//
5+
// Created by Thibault WITTEMBERG on 02/07/2022.
6+
//
7+
8+
public final class AsyncStateMachine<S, E, O>: AsyncSequence, Sendable
29
where S: DSLCompatible & Sendable, E: DSLCompatible & Sendable, O: DSLCompatible {
310
public typealias Element = S
411
public typealias AsyncIterator =
@@ -44,7 +51,7 @@ where S: DSLCompatible & Sendable, E: DSLCompatible & Sendable, O: DSLCompatible
4451
stateMiddlewares: runtime.stateMiddlewares
4552
)
4653

47-
// As channals are retained as long as there is a sender using it,
54+
// As channels are retained as long as there is a sender using it,
4855
// the receiver will also be retained.
4956
// That is why it is necesssary to have a weak reference on the self here.
5057
// Doing so, self will be deallocated event if a channel was using it as a receiver.

Sources/ViewStateMachine.swift renamed to Sources/AsyncStateMachine/ViewStateMachine.swift

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -9,24 +9,24 @@ public class ViewStateMachine<S, E, O>: ObservableObject
99
where S: DSLCompatible & Equatable, E: DSLCompatible, O: DSLCompatible {
1010
@Published public var state: S
1111

12-
let asyncStateMachineSequence: AsyncStateMachineSequence<S, E, O>
12+
let asyncStateMachine: AsyncStateMachine<S, E, O>
1313

14-
public init(asyncStateMachineSequence: AsyncStateMachineSequence<S, E, O>) {
15-
self.asyncStateMachineSequence = asyncStateMachineSequence
16-
self.state = self.asyncStateMachineSequence.initialState
14+
public init(asyncStateMachine: AsyncStateMachine<S, E, O>) {
15+
self.asyncStateMachine = asyncStateMachine
16+
self.state = self.asyncStateMachine.initialState
1717
}
1818

1919
public func send(_ event: E) {
20-
self.asyncStateMachineSequence.send(event)
20+
self.asyncStateMachine.send(event)
2121
}
2222

2323
public func send(
2424
_ event: E,
2525
resumeWhen predicate: @escaping (S) -> Bool
2626
) async {
27-
await withUnsafeContinuation { [asyncStateMachineSequence] (continuation: UnsafeContinuation<Void, Never>) in
27+
await withUnsafeContinuation { [asyncStateMachine] (continuation: UnsafeContinuation<Void, Never>) in
2828
Task {
29-
await asyncStateMachineSequence.engine.register(onTheFly: { state in
29+
await asyncStateMachine.engine.register(onTheFly: { state in
3030
if predicate(state) {
3131
continuation.resume()
3232
// middleware will be unregistered after the predicate has been matched
@@ -35,7 +35,7 @@ where S: DSLCompatible & Equatable, E: DSLCompatible, O: DSLCompatible {
3535
return false
3636
})
3737

38-
asyncStateMachineSequence.send(event)
38+
asyncStateMachine.send(event)
3939
}
4040
}
4141
}
@@ -77,7 +77,7 @@ where S: DSLCompatible & Equatable, E: DSLCompatible, O: DSLCompatible {
7777
}
7878

7979
nonisolated public func start() async {
80-
for await state in self.asyncStateMachineSequence {
80+
for await state in self.asyncStateMachine {
8181
await self.publish(state: state)
8282
}
8383
}
@@ -90,8 +90,8 @@ public extension ViewStateMachine {
9090
func binding(send event: @escaping (S) -> E) -> Binding<S> {
9191
Binding {
9292
self.state
93-
} set: { [asyncStateMachineSequence] value in
94-
asyncStateMachineSequence.send(event(value))
93+
} set: { [asyncStateMachine] value in
94+
asyncStateMachine.send(event(value))
9595
}
9696
}
9797

@@ -102,8 +102,8 @@ public extension ViewStateMachine {
102102
func binding<T>(keypath: KeyPath<S, T>, send event: @escaping (T) -> E) -> Binding<T> {
103103
Binding {
104104
self.state[keyPath: keypath]
105-
} set: { [asyncStateMachineSequence] value in
106-
asyncStateMachineSequence.send(event(value))
105+
} set: { [asyncStateMachine] value in
106+
asyncStateMachine.send(event(value))
107107
}
108108
}
109109

Tests/AsyncStateMachineSequenceTests.swift renamed to Tests/AsyncStateMachine/AsyncStateMachineTests.swift

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
//
2+
// AsyncStateMachineTests.swift
3+
//
4+
//
5+
// Created by Thibault WITTEMBERG on 20/06/2022.
6+
//
7+
18
@testable import AsyncStateMachine
29
import XCTest
310

@@ -71,7 +78,7 @@ enum Output: DSLCompatible, Equatable {
7178
case o3(value: String)
7279
}
7380

74-
final class AsyncStateMachineSequenceTests: XCTestCase {
81+
final class AsyncStateMachineTests: XCTestCase {
7582
// func testPerformance() async {
7683
// let stateMachine = StateMachine<State, Event, Output>(initial: State.s1(value: "s1")) {
7784
// When(states: OneOf {
@@ -187,7 +194,7 @@ final class AsyncStateMachineSequenceTests: XCTestCase {
187194
}
188195
})
189196

190-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
197+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
191198

192199
// When
193200
Task {
@@ -255,8 +262,8 @@ final class AsyncStateMachineSequenceTests: XCTestCase {
255262
let runtime2 = Runtime<State, Event, Output>()
256263
.connectAsReceiver(to: channel)
257264

258-
let asyncStateMachineSequence1 = AsyncStateMachineSequence(stateMachine: stateMachine1, runtime: runtime1)
259-
let asyncStateMachineSequence2 = AsyncStateMachineSequence(stateMachine: stateMachine2, runtime: runtime2)
265+
let asyncStateMachineSequence1 = AsyncStateMachine(stateMachine: stateMachine1, runtime: runtime1)
266+
let asyncStateMachineSequence2 = AsyncStateMachine(stateMachine: stateMachine2, runtime: runtime2)
260267

261268
let firstStatesHaveBeenEmitted = expectation(description: "The first states have been emitted")
262269
firstStatesHaveBeenEmitted.expectedFulfillmentCount = 2
@@ -307,7 +314,7 @@ final class AsyncStateMachineSequenceTests: XCTestCase {
307314
let runtime = Runtime<State, Event, Output>()
308315

309316
// Given
310-
var sut: AsyncStateMachineSequence<State, Event, Output>? = AsyncStateMachineSequence(
317+
var sut: AsyncStateMachine<State, Event, Output>? = AsyncStateMachine(
311318
stateMachine: stateMachine,
312319
runtime: runtime,
313320
onDeinit: { asyncStateMachineSequenceIsDeinit.fulfill() }
@@ -341,7 +348,7 @@ final class AsyncStateMachineSequenceTests: XCTestCase {
341348
.connectAsReceiver(to: channel1)
342349
.connectAsReceiver(to: channel2)
343350

344-
var sut: AsyncStateMachineSequence<State, Event, Output>? = AsyncStateMachineSequence(
351+
var sut: AsyncStateMachine<State, Event, Output>? = AsyncStateMachine(
345352
stateMachine: stateMachine,
346353
runtime: runtime,
347354
onDeinit: { asyncStateMachineSequenceIsDeinit.fulfill() }

Tests/ViewStateMachineTests.swift renamed to Tests/AsyncStateMachine/ViewStateMachineTests.swift

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ final class ViewStateMachineTests: XCTestCase {
4646
eventWasReceived.fulfill()
4747
})
4848

49-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
50-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
49+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
50+
let sut = ViewStateMachine(asyncStateMachine: sequence)
5151

5252
Task {
5353
await sut.start()
@@ -85,8 +85,8 @@ final class ViewStateMachineTests: XCTestCase {
8585
let runtime = Runtime<State, Event, Output>()
8686
.map(output: .o1, to: { Event.e2 })
8787

88-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
89-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
88+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
89+
let sut = ViewStateMachine(asyncStateMachine: sequence)
9090

9191
Task {
9292
await sut.start()
@@ -122,8 +122,8 @@ final class ViewStateMachineTests: XCTestCase {
122122
let runtime = Runtime<State, Event, Output>()
123123
.map(output: .o1, to: { Event.e2 })
124124

125-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
126-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
125+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
126+
let sut = ViewStateMachine(asyncStateMachine: sequence)
127127

128128
Task {
129129
await sut.start()
@@ -159,8 +159,8 @@ final class ViewStateMachineTests: XCTestCase {
159159
let runtime = Runtime<State, Event, Output>()
160160
.map(output: .o1, to: { Event.e2 })
161161

162-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
163-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
162+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
163+
let sut = ViewStateMachine(asyncStateMachine: sequence)
164164

165165
Task {
166166
await sut.start()
@@ -196,8 +196,8 @@ final class ViewStateMachineTests: XCTestCase {
196196
let runtime = Runtime<State, Event, Output>()
197197
.map(output: .o1, to: { Event.e2 })
198198

199-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
200-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
199+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
200+
let sut = ViewStateMachine(asyncStateMachine: sequence)
201201

202202
Task {
203203
await sut.start()
@@ -224,8 +224,8 @@ final class ViewStateMachineTests: XCTestCase {
224224
eventWasReceived.fulfill()
225225
})
226226

227-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
228-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
227+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
228+
let sut = ViewStateMachine(asyncStateMachine: sequence)
229229

230230
Task {
231231
await sut.start()
@@ -259,8 +259,8 @@ final class ViewStateMachineTests: XCTestCase {
259259
eventWasReceived.fulfill()
260260
})
261261

262-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
263-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
262+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
263+
let sut = ViewStateMachine(asyncStateMachine: sequence)
264264

265265
Task {
266266
await sut.start()
@@ -299,8 +299,8 @@ final class ViewStateMachineTests: XCTestCase {
299299
eventWasReceived.fulfill()
300300
})
301301

302-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
303-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
302+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
303+
let sut = ViewStateMachine(asyncStateMachine: sequence)
304304

305305
Task {
306306
await sut.start()
@@ -343,8 +343,8 @@ final class ViewStateMachineTests: XCTestCase {
343343
eventWasReceived.fulfill()
344344
})
345345

346-
let sequence = AsyncStateMachineSequence(stateMachine: stateMachine, runtime: runtime)
347-
let sut = ViewStateMachine(asyncStateMachineSequence: sequence)
346+
let sequence = AsyncStateMachine(stateMachine: stateMachine, runtime: runtime)
347+
let sut = ViewStateMachine(asyncStateMachine: sequence)
348348

349349
Task {
350350
await sut.start()

0 commit comments

Comments
 (0)