diff --git a/Playgrounds/Operators.playground/Contents.swift b/Playgrounds/01 - Protocol Free Design.playground/Pages/01-Type Level vs Value Level.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Operators.playground/Contents.swift
rename to Playgrounds/01 - Protocol Free Design.playground/Pages/01-Type Level vs Value Level.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Operators.playground/timeline.xctimeline b/Playgrounds/01 - Protocol Free Design.playground/Pages/01-Type Level vs Value Level.xcplaygroundpage/timeline.xctimeline
similarity index 100%
rename from Playgrounds/Operators.playground/timeline.xctimeline
rename to Playgrounds/01 - Protocol Free Design.playground/Pages/01-Type Level vs Value Level.xcplaygroundpage/timeline.xctimeline
diff --git a/Playgrounds/Operators.playground/Pages/01-Map.xcplaygroundpage/Contents.swift b/Playgrounds/01 - Protocol Free Design.playground/Pages/02-Witnesses.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Operators.playground/Pages/01-Map.xcplaygroundpage/Contents.swift
rename to Playgrounds/01 - Protocol Free Design.playground/Pages/02-Witnesses.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Operators.playground/contents.xcplayground b/Playgrounds/01 - Protocol Free Design.playground/contents.xcplayground
similarity index 100%
rename from Playgrounds/Operators.playground/contents.xcplayground
rename to Playgrounds/01 - Protocol Free Design.playground/contents.xcplayground
diff --git a/Playgrounds/FreeCombine.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/01 - Protocol Free Design.playground/playground.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from Playgrounds/FreeCombine.playground/playground.xcworkspace/contents.xcworkspacedata
rename to Playgrounds/01 - Protocol Free Design.playground/playground.xcworkspace/contents.xcworkspacedata
diff --git a/Playgrounds/Publishers.playground/Contents.swift b/Playgrounds/02 - Continuation Passing Style.playground/Pages/01 - Future.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Contents.swift
rename to Playgrounds/02 - Continuation Passing Style.playground/Pages/01 - Future.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Operators.playground/Pages/02-FlatMap.xcplaygroundpage/Contents.swift b/Playgrounds/02 - Continuation Passing Style.playground/Pages/02 - Continuation.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Operators.playground/Pages/02-FlatMap.xcplaygroundpage/Contents.swift
rename to Playgrounds/02 - Continuation Passing Style.playground/Pages/02 - Continuation.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Operators.playground/Pages/03-Zip.xcplaygroundpage/Contents.swift b/Playgrounds/02 - Continuation Passing Style.playground/Pages/03 - Modifications Of Continuation.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Operators.playground/Pages/03-Zip.xcplaygroundpage/Contents.swift
rename to Playgrounds/02 - Continuation Passing Style.playground/Pages/03 - Modifications Of Continuation.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Operators.playground/Pages/04-Reduce.xcplaygroundpage/Contents.swift b/Playgrounds/02 - Continuation Passing Style.playground/Pages/04 - Publishers.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Operators.playground/Pages/04-Reduce.xcplaygroundpage/Contents.swift
rename to Playgrounds/02 - Continuation Passing Style.playground/Pages/04 - Publishers.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Operators.playground/Pages/05-Filter.xcplaygroundpage/Contents.swift b/Playgrounds/02 - Continuation Passing Style.playground/Pages/05 - Duality of Direct Style vs Continuation Passing Style.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Operators.playground/Pages/05-Filter.xcplaygroundpage/Contents.swift
rename to Playgrounds/02 - Continuation Passing Style.playground/Pages/05 - Duality of Direct Style vs Continuation Passing Style.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/02 - Continuation Passing Style.playground/contents.xcplayground b/Playgrounds/02 - Continuation Passing Style.playground/contents.xcplayground
new file mode 100644
index 0000000..7627317
--- /dev/null
+++ b/Playgrounds/02 - Continuation Passing Style.playground/contents.xcplayground
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Playgrounds/Operators.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/02 - Continuation Passing Style.playground/playground.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from Playgrounds/Operators.playground/playground.xcworkspace/contents.xcworkspacedata
rename to Playgrounds/02 - Continuation Passing Style.playground/playground.xcworkspace/contents.xcworkspacedata
diff --git a/Playgrounds/Publishers.playground/timeline.xctimeline b/Playgrounds/02 - Continuation Passing Style.playground/timeline.xctimeline
similarity index 100%
rename from Playgrounds/Publishers.playground/timeline.xctimeline
rename to Playgrounds/02 - Continuation Passing Style.playground/timeline.xctimeline
diff --git a/Playgrounds/FreeCombine.playground/Pages/00a-Introduction (Examples).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/00a-Introduction (Examples).xcplaygroundpage/Contents.swift
similarity index 98%
rename from Playgrounds/FreeCombine.playground/Pages/00a-Introduction (Examples).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/00a-Introduction (Examples).xcplaygroundpage/Contents.swift
index 5ed7df4..0295176 100644
--- a/Playgrounds/FreeCombine.playground/Pages/00a-Introduction (Examples).xcplaygroundpage/Contents.swift
+++ b/Playgrounds/03 - FreeCombine.playground/Pages/00a-Introduction (Examples).xcplaygroundpage/Contents.swift
@@ -55,8 +55,8 @@ import FreeCombine
import _Concurrency
Task {
- let fsubject1 = await FreeCombine.PassthroughSubject(Int.self)
- let fsubject2 = await FreeCombine.PassthroughSubject(String.self)
+ let fsubject1 = await PassthroughSubject(Int.self)
+ let fsubject2 = await PassthroughSubject(String.self)
let fseq1 = "abcdefghijklmnopqrstuvwxyz".asyncPublisher
let fseq2 = (1 ... 100).asyncPublisher
diff --git a/Playgrounds/FreeCombine.playground/Pages/00b-Introduction (Requirements).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/00b-Introduction (Requirements).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/00b-Introduction (Requirements).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/00b-Introduction (Requirements).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/00c-Introduction (Supply and Demand).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/00c-Introduction (Supply and Demand).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/00c-Introduction (Supply and Demand).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/00c-Introduction (Supply and Demand).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01a-Deriving FreeCombine (Base).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01a-Deriving FreeCombine (Base).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01a-Deriving FreeCombine (Base).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01a-Deriving FreeCombine (Base).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01b-Deriving FreeCombine (enum Demand).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01b-Deriving FreeCombine (enum Demand).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01b-Deriving FreeCombine (enum Demand).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01b-Deriving FreeCombine (enum Demand).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01c-Deriving FreeCombine (async eliminates Subscription).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01c-Deriving FreeCombine (async eliminates Subscription).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01c-Deriving FreeCombine (async eliminates Subscription).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01c-Deriving FreeCombine (async eliminates Subscription).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01d-Deriving FreeCombine (simplify Subscriber to one func).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01d-Deriving FreeCombine (simplify Subscriber to one func).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01d-Deriving FreeCombine (simplify Subscriber to one func).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01d-Deriving FreeCombine (simplify Subscriber to one func).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01e-Deriving FreeCombine (eliminate Subscriber into Publisher).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01e-Deriving FreeCombine (eliminate Subscriber into Publisher).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01e-Deriving FreeCombine (eliminate Subscriber into Publisher).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01e-Deriving FreeCombine (eliminate Subscriber into Publisher).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01f-Deriving FreeCombine (add Task as Cancellation).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01f-Deriving FreeCombine (add Task as Cancellation).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01f-Deriving FreeCombine (add Task as Cancellation).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01f-Deriving FreeCombine (add Task as Cancellation).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01g-Deriving FreeCombine (cleanup).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01g-Deriving FreeCombine (cleanup).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01g-Deriving FreeCombine (cleanup).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01g-Deriving FreeCombine (cleanup).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Pages/01h-Deriving FreeCombine (convert Publisher protocol to struct).xcplaygroundpage/Contents.swift b/Playgrounds/03 - FreeCombine.playground/Pages/01h-Deriving FreeCombine (convert Publisher protocol to struct).xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Pages/01h-Deriving FreeCombine (convert Publisher protocol to struct).xcplaygroundpage/Contents.swift
rename to Playgrounds/03 - FreeCombine.playground/Pages/01h-Deriving FreeCombine (convert Publisher protocol to struct).xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/FreeCombine.playground/Resources/CombineReturnTypes.png b/Playgrounds/03 - FreeCombine.playground/Resources/CombineReturnTypes.png
similarity index 100%
rename from Playgrounds/FreeCombine.playground/Resources/CombineReturnTypes.png
rename to Playgrounds/03 - FreeCombine.playground/Resources/CombineReturnTypes.png
diff --git a/Playgrounds/FreeCombine.playground/contents.xcplayground b/Playgrounds/03 - FreeCombine.playground/contents.xcplayground
similarity index 100%
rename from Playgrounds/FreeCombine.playground/contents.xcplayground
rename to Playgrounds/03 - FreeCombine.playground/contents.xcplayground
diff --git a/Playgrounds/Publishers.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/03 - FreeCombine.playground/playground.xcworkspace/contents.xcworkspacedata
similarity index 100%
rename from Playgrounds/Publishers.playground/playground.xcworkspace/contents.xcworkspacedata
rename to Playgrounds/03 - FreeCombine.playground/playground.xcworkspace/contents.xcworkspacedata
diff --git a/Playgrounds/04 - Publishers.playground/Contents.swift b/Playgrounds/04 - Publishers.playground/Contents.swift
new file mode 100644
index 0000000..9d86688
--- /dev/null
+++ b/Playgrounds/04 - Publishers.playground/Contents.swift
@@ -0,0 +1,3 @@
+import UIKit
+
+var greeting = "Hello, playground"
diff --git a/Playgrounds/Publishers.playground/Pages/01-Just.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/01-Just.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/01-Just.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/01-Just.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/02-Empty.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/02-Empty.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/02-Empty.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/02-Empty.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/03-Fail.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/03-Fail.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/03-Fail.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/03-Fail.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/04-Unfolded.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/04-Unfolded.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/04-Unfolded.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/04-Unfolded.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/05-Deferred.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/05-Deferred.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/05-Deferred.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/05-Deferred.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/06-Concat.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/06-Concat.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/06-Concat.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/06-Concat.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/07-Zipped.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/07-Zipped.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/07-Zipped.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/07-Zipped.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/08-Merged.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/08-Merged.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/08-Merged.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/08-Merged.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/09-CombineLatest.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/09-CombineLatest.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/09-CombineLatest.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/09-CombineLatest.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/10-Heartbeat.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/10-Heartbeat.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/10-Heartbeat.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/10-Heartbeat.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/Pages/11-FireAndForget.xcplaygroundpage/Contents.swift b/Playgrounds/04 - Publishers.playground/Pages/11-FireAndForget.xcplaygroundpage/Contents.swift
similarity index 100%
rename from Playgrounds/Publishers.playground/Pages/11-FireAndForget.xcplaygroundpage/Contents.swift
rename to Playgrounds/04 - Publishers.playground/Pages/11-FireAndForget.xcplaygroundpage/Contents.swift
diff --git a/Playgrounds/Publishers.playground/contents.xcplayground b/Playgrounds/04 - Publishers.playground/contents.xcplayground
similarity index 100%
rename from Playgrounds/Publishers.playground/contents.xcplayground
rename to Playgrounds/04 - Publishers.playground/contents.xcplayground
diff --git a/Playgrounds/04 - Publishers.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/04 - Publishers.playground/playground.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/Playgrounds/04 - Publishers.playground/playground.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Playgrounds/04 - Publishers.playground/timeline.xctimeline b/Playgrounds/04 - Publishers.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/Playgrounds/04 - Publishers.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/Playgrounds/05 - Operators.playground/Contents.swift b/Playgrounds/05 - Operators.playground/Contents.swift
new file mode 100644
index 0000000..9d86688
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/Contents.swift
@@ -0,0 +1,3 @@
+import UIKit
+
+var greeting = "Hello, playground"
diff --git a/Playgrounds/05 - Operators.playground/Pages/01-Map.xcplaygroundpage/Contents.swift b/Playgrounds/05 - Operators.playground/Pages/01-Map.xcplaygroundpage/Contents.swift
new file mode 100644
index 0000000..5275afb
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/Pages/01-Map.xcplaygroundpage/Contents.swift
@@ -0,0 +1,7 @@
+//: [Previous](@previous)
+
+import Foundation
+
+var greeting = "Hello, playground"
+
+//: [Next](@next)
diff --git a/Playgrounds/05 - Operators.playground/Pages/02-FlatMap.xcplaygroundpage/Contents.swift b/Playgrounds/05 - Operators.playground/Pages/02-FlatMap.xcplaygroundpage/Contents.swift
new file mode 100644
index 0000000..5275afb
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/Pages/02-FlatMap.xcplaygroundpage/Contents.swift
@@ -0,0 +1,7 @@
+//: [Previous](@previous)
+
+import Foundation
+
+var greeting = "Hello, playground"
+
+//: [Next](@next)
diff --git a/Playgrounds/05 - Operators.playground/Pages/03-Zip.xcplaygroundpage/Contents.swift b/Playgrounds/05 - Operators.playground/Pages/03-Zip.xcplaygroundpage/Contents.swift
new file mode 100644
index 0000000..5275afb
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/Pages/03-Zip.xcplaygroundpage/Contents.swift
@@ -0,0 +1,7 @@
+//: [Previous](@previous)
+
+import Foundation
+
+var greeting = "Hello, playground"
+
+//: [Next](@next)
diff --git a/Playgrounds/05 - Operators.playground/Pages/04-Reduce.xcplaygroundpage/Contents.swift b/Playgrounds/05 - Operators.playground/Pages/04-Reduce.xcplaygroundpage/Contents.swift
new file mode 100644
index 0000000..5275afb
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/Pages/04-Reduce.xcplaygroundpage/Contents.swift
@@ -0,0 +1,7 @@
+//: [Previous](@previous)
+
+import Foundation
+
+var greeting = "Hello, playground"
+
+//: [Next](@next)
diff --git a/Playgrounds/05 - Operators.playground/Pages/05-Filter.xcplaygroundpage/Contents.swift b/Playgrounds/05 - Operators.playground/Pages/05-Filter.xcplaygroundpage/Contents.swift
new file mode 100644
index 0000000..5275afb
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/Pages/05-Filter.xcplaygroundpage/Contents.swift
@@ -0,0 +1,7 @@
+//: [Previous](@previous)
+
+import Foundation
+
+var greeting = "Hello, playground"
+
+//: [Next](@next)
diff --git a/Playgrounds/05 - Operators.playground/contents.xcplayground b/Playgrounds/05 - Operators.playground/contents.xcplayground
new file mode 100644
index 0000000..7627317
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/contents.xcplayground
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/Playgrounds/05 - Operators.playground/playground.xcworkspace/contents.xcworkspacedata b/Playgrounds/05 - Operators.playground/playground.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/playground.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/Playgrounds/05 - Operators.playground/timeline.xctimeline b/Playgrounds/05 - Operators.playground/timeline.xctimeline
new file mode 100644
index 0000000..bf468af
--- /dev/null
+++ b/Playgrounds/05 - Operators.playground/timeline.xctimeline
@@ -0,0 +1,6 @@
+
+
+
+
+
diff --git a/Sources/FreeCombine/Channel/Channel.swift b/Sources/FreeCombine/Channel/Channel.swift
index c5ae632..77e72d3 100644
--- a/Sources/FreeCombine/Channel/Channel.swift
+++ b/Sources/FreeCombine/Channel/Channel.swift
@@ -19,13 +19,11 @@ public struct Channel: AsyncSequence {
public init(
_: Element.Type = Element.self,
- buffering: AsyncStream.Continuation.BufferingPolicy = .bufferingOldest(1),
- onTermination: (@Sendable (AsyncStream.Continuation.Termination) -> Void)? = .none
+ buffering: AsyncStream.Continuation.BufferingPolicy = .bufferingOldest(1)
) {
var localContinuation: AsyncStream.Continuation! = .none
stream = .init(bufferingPolicy: buffering) { continuation in
localContinuation = continuation
- localContinuation.onTermination = onTermination
}
continuation = localContinuation
}
@@ -79,7 +77,6 @@ public extension Channel {
func stateTask(
initialState: @escaping (Self) async -> State,
- onCancel: @Sendable @escaping () -> Void = { },
reducer: Reducer
) async -> StateTask {
var stateTask: StateTask!
@@ -88,7 +85,6 @@ public extension Channel {
channel: self,
initialState: initialState,
onStartup: stateTaskContinuation,
- onCancel: onCancel,
reducer: reducer
)
}
@@ -98,14 +94,12 @@ public extension Channel {
func stateTask(
initialState: @escaping (Self) async -> State,
onStartup: UnsafeContinuation? = .none,
- onCancel: @Sendable @escaping () -> Void = { },
reducer: Reducer
) -> StateTask {
.init(
channel: self,
initialState: initialState,
onStartup: onStartup,
- onCancel: onCancel,
reducer: reducer
)
}
diff --git a/Sources/FreeCombine/Combinator/CombineLatestState.swift b/Sources/FreeCombine/Combinator/CombineLatestState.swift
new file mode 100644
index 0000000..b53458e
--- /dev/null
+++ b/Sources/FreeCombine/Combinator/CombineLatestState.swift
@@ -0,0 +1,120 @@
+//
+// CombineLatestState.swift
+//
+//
+// Created by Van Simmons on 6/4/22.
+//
+struct CombineLatestState: CombinatorState {
+ typealias CombinatorAction = Self.Action
+ enum Action {
+ case setLeft(AsyncStream.Result, UnsafeContinuation)
+ case setRight(AsyncStream.Result, UnsafeContinuation)
+ }
+
+ let downstream: (AsyncStream<(Left?, Right?)>.Result) async throws -> Demand
+ let leftCancellable: Cancellable
+ let rightCancellable: Cancellable
+
+ var mostRecentDemand: Demand
+ var left: (value: Left?, continuation: UnsafeContinuation)? = .none
+ var right: (value: Right?, continuation: UnsafeContinuation)? = .none
+ var leftComplete = false
+ var rightComplete = false
+
+ init(
+ channel: Channel.Action>,
+ downstream: @escaping (AsyncStream<(Left?, Right?)>.Result) async throws -> Demand,
+ mostRecentDemand: Demand = .more,
+ left: Publisher,
+ right: Publisher
+ ) async {
+ self.downstream = downstream
+ self.mostRecentDemand = mostRecentDemand
+ self.leftCancellable = await channel.consume(publisher: left, using: CombineLatestState.Action.setLeft)
+ self.rightCancellable = await channel.consume(publisher: right, using: CombineLatestState.Action.setRight)
+ }
+
+ static func create(
+ mostRecentDemand: Demand = .more,
+ left: Publisher,
+ right: Publisher
+ ) -> (@escaping (AsyncStream<(Left?, Right?)>.Result) async throws -> Demand) -> (Channel.Action>) async -> Self {
+ { downstream in { channel in
+ await .init(channel: channel, downstream: downstream, left: left, right: right)
+ } }
+ }
+
+ static func complete(state: inout Self, completion: Reducer.Completion) async -> Void {
+ state.leftCancellable.cancel()
+ state.left?.continuation.resume(returning: .done)
+ state.rightCancellable.cancel()
+ state.right?.continuation.resume(returning: .done)
+ switch completion {
+ case .cancel:
+ _ = try? await state.downstream(.completion(.cancelled))
+ case .exit, .termination:
+ _ = try? await state.downstream(.completion(.finished))
+ case let .failure(error):
+ _ = try? await state.downstream(.completion(.failure(error)))
+ }
+ }
+
+ static func reduce(`self`: inout Self, action: Self.Action) async throws -> Reducer.Effect {
+ guard !Task.isCancelled else { return .completion(.cancel) }
+ return try await `self`.reduce(action: action)
+ }
+
+ private mutating func reduce(
+ action: Self.Action
+ ) async throws -> Reducer.Effect {
+ switch action {
+ case let .setLeft(leftResult, leftContinuation):
+ if mostRecentDemand == .done { leftContinuation.resume(returning: .done) }
+ else { return try await handleLeft(leftResult, leftContinuation) }
+ case let .setRight(rightResult, rightContinuation):
+ if mostRecentDemand == .done { rightContinuation.resume(returning: .done) }
+ else { return try await handleRight(rightResult, rightContinuation) }
+ }
+ return .none
+ }
+
+ private mutating func handleLeft(
+ _ leftResult: AsyncStream.Result,
+ _ leftContinuation: UnsafeContinuation
+ ) async throws -> Reducer.Effect {
+ switch leftResult {
+ case let .value((value)):
+ left = (value, leftContinuation)
+ guard !Task.isCancelled else {
+ leftContinuation.resume(returning: .done)
+ return .completion(.cancel)
+ }
+ mostRecentDemand = try await downstream(.value((value, right?.value)))
+ leftContinuation.resume(returning: mostRecentDemand)
+ return .none
+ case .completion(_):
+ leftComplete = true
+ return leftComplete && rightComplete ? .completion(.exit) : .none
+ }
+ }
+
+ private mutating func handleRight(
+ _ rightResult: AsyncStream.Result,
+ _ rightContinuation: UnsafeContinuation
+ ) async throws -> Reducer.Effect {
+ switch rightResult {
+ case let .value((value)):
+ right = (value, rightContinuation)
+ guard !Task.isCancelled else {
+ rightContinuation.resume(returning: .done)
+ return .completion(.cancel)
+ }
+ mostRecentDemand = try await downstream(.value((left?.value, value)))
+ rightContinuation.resume(returning: mostRecentDemand)
+ return .none
+ case .completion(_) :
+ rightComplete = true
+ return leftComplete && rightComplete ? .completion(.exit) : .none
+ }
+ }
+}
diff --git a/Sources/FreeCombine/Filter/DropFirst.swift b/Sources/FreeCombine/Filter/DropFirst.swift
new file mode 100644
index 0000000..45dd66b
--- /dev/null
+++ b/Sources/FreeCombine/Filter/DropFirst.swift
@@ -0,0 +1,25 @@
+//
+// File.swift
+//
+//
+// Created by Van Simmons on 6/4/22.
+//
+public extension Publisher {
+ func dropFirst(
+ _ count: Int = 1
+ ) -> Self {
+ .init { continuation, downstream in
+ let currentValue: ValueRef = ValueRef(value: count + 1)
+ return self(onStartup: continuation) { r in
+ let current = await currentValue.value - 1
+ await currentValue.set(value: max(0, current))
+ switch r {
+ case .value:
+ guard current <= 0 else { return .more }
+ return try await downstream(r)
+ case let .completion(value):
+ return try await downstream(.completion(value))
+ } }
+ }
+ }
+}
diff --git a/Sources/FreeCombine/Publishers/Combinator.swift b/Sources/FreeCombine/Publishers/Combinator.swift
index 08c1a91..e445716 100644
--- a/Sources/FreeCombine/Publishers/Combinator.swift
+++ b/Sources/FreeCombine/Publishers/Combinator.swift
@@ -12,13 +12,11 @@ public protocol CombinatorState {
public func Combinator(
initialState: @escaping (@escaping (AsyncStream