Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New name for DeferredFutureSingle and DeferredFutureMaybe #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
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