Skip to content

Commit

Permalink
New name for DeferredFutureSingle and DeferredFutureMaybe
Browse files Browse the repository at this point in the history
  • Loading branch information
groue committed Oct 12, 2020
1 parent 6a9da5f commit 11334af
Show file tree
Hide file tree
Showing 9 changed files with 220 additions and 219 deletions.
24 changes: 14 additions & 10 deletions Documentation/Maybe.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ There are a few ways to get such a maybe publisher:

The consequences of using `uncheckedMaybe()` on a publisher that does not publish exactly zero value, or one value, or an error, are undefined.

See also [Basic Maybe Publishers], [TraitPublishers.Maybe] and [TraitSubscriptions.Maybe].
See also [Basic Maybe Publishers], [DeferredFutureMaybe] and [TraitSubscriptions.Maybe].

### Basic Maybe Publishers

Expand Down Expand Up @@ -178,16 +178,16 @@ func namePublisher() -> AnyMaybePublisher<String, Error> {
}
```

### TraitPublishers.Maybe
### DeferredFutureMaybe

`TraitPublishers.Maybe` is a ready-made Combine [Publisher] which allows you to dynamically send success or failure events.
`DeferredFutureMaybe` is a ready-made Combine [Publisher] which allows you to dynamically send success or failure events.

It lets you easily create custom maybe publishers to wrap most non-publisher asynchronous work.

You create this publisher by providing a closure. This closure runs when the publisher is subscribed to. It returns a cancellable object in which you define any cleanup actions to execute when the publisher completes, or when the subscription is canceled.

```swift
let publisher = TraitPublishers.Maybe<String, MyError> { promise in
let publisher = DeferredFutureMaybe<String, MyError> { promise in
// Eventually send completion event, now or in the future:
promise(.finished)
// OR
Expand All @@ -201,15 +201,17 @@ let publisher = TraitPublishers.Maybe<String, MyError> { promise in
}
```

`TraitPublishers.Maybe` is a "deferred" maybe publisher:
`DeferredFutureMaybe` is a "deferred future" maybe publisher, because:

- Nothing happens until the publisher is subscribed to. A new job starts on each subscription.
- It can complete right on subscription, or at any time in the future.
- Like the [Deferred] Combine publisher, nothing happens until `DeferredFutureMaybe` is subscribed to. A new job starts on each subscription.
- Like the [Future] Combine publisher, It can complete any time, immediately after subscription, or in the future.

When needed, `TraitPublishers.Maybe` can forward its job to another maybe publisher:
However, `DeferredFutureMaybe` allows cancellation cleanup.

When needed, `DeferredFutureMaybe` can forward its job to another maybe publisher:

```swift
let publisher = TraitPublishers.Maybe<String, MyError> { promise in
let publisher = DeferredFutureMaybe<String, MyError> { promise in
return otherMaybePublisher.sinkMaybe(receive: promise)
}
```
Expand Down Expand Up @@ -317,7 +319,9 @@ class MyViewController: UIViewController {
[`sinkMaybe(receive:)`]: #sinkmaybereceive
[Building Maybe Publishers]: #building-maybe-publishers
[Basic Maybe Publishers]: #basic-maybe-publishers
[TraitPublishers.Maybe]: #TraitPublishersmaybe
[DeferredFutureMaybe]: #deferredfuturemaybe
[TraitSubscriptions.Maybe]: #traitsubscriptionsmaybe
[Publisher]: https://developer.apple.com/documentation/combine/publisher
[Subscription]: https://developer.apple.com/documentation/combine/subscription
[Deferred]: https://developer.apple.com/documentation/combine/deferred
[Future]: https://developer.apple.com/documentation/combine/future
24 changes: 14 additions & 10 deletions Documentation/Single.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ There are a few ways to get such a single publisher:

The consequences of using `uncheckedSingle()` on a publisher that does not publish exactly one value, or an error, are undefined.

See also [Basic Single Publishers], [TraitPublishers.Single] and [TraitSubscriptions.Single].
See also [Basic Single Publishers], [DeferredFutureSingle] and [TraitSubscriptions.Single].

### Basic Single Publishers

Expand All @@ -202,16 +202,16 @@ func namePublisher() -> AnySinglePublisher<String, Error> {
}
```

### TraitPublishers.Single
### DeferredFutureSingle

`TraitPublishers.Single` is a ready-made Combine [Publisher] which which allows you to dynamically send success or failure events.
`DeferredFutureSingle` is a ready-made Combine [Publisher] which allows you to dynamically send success or failure events.

It lets you easily create custom single publishers to wrap most non-publisher asynchronous work.

You create this publisher by providing a closure. This closure runs when the publisher is subscribed to. It returns a cancellable object in which you define any cleanup actions to execute when the publisher completes, or when the subscription is canceled.

```swift
let publisher = TraitPublishers.Single<String, MyError> { promise in
let publisher = DeferredFutureSingle<String, MyError> { promise in
// Eventually send completion event, now or in the future:
promise(.success("Alice"))
// OR
Expand All @@ -223,15 +223,17 @@ let publisher = TraitPublishers.Single<String, MyError> { promise in
}
```

`TraitPublishers.Single` can be seen as a "deferred future" single publisher:
`DeferredFutureSingle` is a "deferred future" single publisher, because:

- Nothing happens until the publisher is subscribed to. A new job starts on each subscription.
- It can complete right on subscription, or at any time in the future.
- Like the [Deferred] Combine publisher, nothing happens until `DeferredFutureSingle` is subscribed to. A new job starts on each subscription.
- Like the [Future] Combine publisher, It can complete any time, immediately after subscription, or in the future.

When needed, `TraitPublishers.Single` can forward its job to another single publisher:
However, `DeferredFutureSingle` allows cancellation cleanup.

When needed, `DeferredFutureSingle` can forward its job to another single publisher:

```swift
let publisher = TraitPublishers.Single<String, MyError> { promise in
let publisher = DeferredFutureSingle<String, MyError> { promise in
return otherSinglePublisher.sinkSingle(receive: promise)
}
```
Expand Down Expand Up @@ -340,7 +342,9 @@ class MyViewController: UIViewController {
[Composing Single Publishers]: #composing-single-publishers
[Building Single Publishers]: #building-single-publishers
[Basic Single Publishers]: #basic-single-publishers
[TraitPublishers.Single]: #TraitPublisherssingle
[DeferredFutureSingle]: #deferredfuturesingle
[TraitSubscriptions.Single]: #traitsubscriptionssingle
[Publisher]: https://developer.apple.com/documentation/combine/publisher
[Subscription]: https://developer.apple.com/documentation/combine/subscription
[Deferred]: https://developer.apple.com/documentation/combine/deferred
[Future]: https://developer.apple.com/documentation/combine/future
75 changes: 75 additions & 0 deletions Sources/CombineTraits/DeferredFutureMaybe.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import Combine

/// `DeferredFutureMaybe` is a ready-made Combine Publisher which allows you to
/// dynamically send success or failure events.
///
/// It lets you easily create custom maybe publishers to wrap most
/// non-publisher asynchronous work.
///
/// You create this publisher by providing a closure. This closure runs when
/// the publisher is subscribed to. It returns a cancellable object in which
/// you define any cleanup actions to execute when the publisher completes,
/// or when the subscription is canceled.
///
/// let publisher = DeferredFutureMaybe<String, MyError> { promise in
/// // Eventually send completion event, now or in the future:
/// promise(.finished)
/// // OR
/// promise(.success("Alice"))
/// // OR
/// promise(.failure(MyError()))
///
/// return AnyCancellable {
/// // Perform cleanup
/// }
/// }
///
/// `DeferredFutureMaybe` is a "deferred" maybe publisher:
///
/// - Nothing happens until the publisher is subscribed to. A new job starts
/// on each subscription.
/// - It can complete right on subscription, or at any time in the future.
///
/// When needed, `DeferredFutureMaybe` can forward its job to another
/// maybe publisher:
///
/// let publisher = DeferredFutureMaybe<String, MyError> { promise in
/// return otherMaybePublisher.sinkMaybe(receive: promise)
/// }
public struct DeferredFutureMaybe<Output, Failure: Error>: MaybePublisher {
public typealias Promise = (MaybeResult<Output, Failure>) -> Void
typealias Start = (@escaping Promise) -> AnyCancellable
let start: Start

// TODO: doc
// TODO: allow any cancellable
public init(_ start: @escaping (@escaping Promise) -> AnyCancellable) {
self.start = start
}

public func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
let subscription = Subscription(
downstream: subscriber,
context: start)
subscriber.receive(subscription: subscription)
}

private class Subscription<Downstream: Subscriber>:
TraitSubscriptions.Maybe<Downstream, Start>
where
Downstream.Input == Output,
Downstream.Failure == Failure
{
var cancellable: AnyCancellable?

override func start(with start: @escaping Start) {
cancellable = start { result in
self.receive(result)
}
}

override func didCancel(with start: @escaping Start) {
cancellable?.cancel()
}
}
}
73 changes: 73 additions & 0 deletions Sources/CombineTraits/DeferredFutureSingle.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import Combine

/// `DeferredFutureSingle` is a ready-made Combine Publisher which allows you to
/// dynamically send success or failure events.
///
/// It lets you easily create custom single publishers to wrap most
/// non-publisher asynchronous work.
///
/// You create this publisher by providing a closure. This closure runs when
/// the publisher is subscribed to. It returns a cancellable object in which
/// you define any cleanup actions to execute when the publisher completes,
/// or when the subscription is canceled.
///
/// let publisher = DeferredFutureSingle<String, MyError> { promise in
/// // Eventually send completion event, now or in the future:
/// promise(.success("Alice"))
/// // OR
/// promise(.failure(MyError()))
///
/// return AnyCancellable {
/// // Perform cleanup
/// }
/// }
///
/// `DeferredFutureSingle` can be seen as a "deferred future"
/// single publisher:
///
/// - Nothing happens until the publisher is subscribed to. A new job starts
/// on each subscription.
/// - It can complete right on subscription, or at any time in the future.
///
/// When needed, `DeferredFutureSingle` can forward its job to another
/// single publisher:
///
/// let publisher = DeferredFutureSingle<String, MyError> { promise in
/// return otherSinglePublisher.sinkSingle(receive: promise)
/// }
public struct DeferredFutureSingle<Output, Failure: Error>: SinglePublisher {
public typealias Promise = (Result<Output, Failure>) -> Void
typealias Start = (@escaping Promise) -> AnyCancellable
let start: Start

// TODO: doc
public init(_ start: @escaping (@escaping Promise) -> AnyCancellable) {
self.start = start
}

public func receive<S>(subscriber: S) where S: Subscriber, Failure == S.Failure, Output == S.Input {
let subscription = Subscription(
downstream: subscriber,
context: start)
subscriber.receive(subscription: subscription)
}

private class Subscription<Downstream: Subscriber>:
TraitSubscriptions.Single<Downstream, Start>
where
Downstream.Input == Output,
Downstream.Failure == Failure
{
var cancellable: AnyCancellable?

override func start(with start: @escaping Start) {
cancellable = start { result in
self.receive(result)
}
}

override func didCancel(with start: @escaping Start) {
cancellable?.cancel()
}
}
}
2 changes: 0 additions & 2 deletions Sources/CombineTraits/TraitPublishers/TraitPublishers.swift

This file was deleted.

77 changes: 0 additions & 77 deletions Sources/CombineTraits/TraitPublishers/TraitPublishersMaybe.swift

This file was deleted.

Loading

0 comments on commit 11334af

Please sign in to comment.