Skip to content

Commit 9372179

Browse files
committed
Move to 6.1 and update proposal
1 parent b30ec17 commit 9372179

File tree

4 files changed

+124
-18
lines changed

4 files changed

+124
-18
lines changed

Evolution/0016-mutli-producer-single-consumer-channel.md

+64-8
Original file line numberDiff line numberDiff line change
@@ -393,38 +393,44 @@ producer has been terminated will result in an error thrown from the send method
393393
## Detailed design
394394

395395
```swift
396-
#if compiler(>=6.0)
396+
#if compiler(>=6.1)
397397
/// An error that is thrown from the various `send` methods of the
398398
/// ``MultiProducerSingleConsumerChannel/Source``.
399399
///
400400
/// This error is thrown when the channel is already finished when
401401
/// trying to send new elements to the source.
402402
public struct MultiProducerSingleConsumerChannelAlreadyFinishedError: Error { }
403403

404-
/// A multi producer single consumer channel.
404+
/// A multi-producer single-consumer channel.
405405
///
406406
/// The ``MultiProducerSingleConsumerChannel`` provides a ``MultiProducerSingleConsumerChannel/Source`` to
407407
/// send values to the channel. The channel supports different back pressure strategies to control the
408408
/// buffering and demand. The channel will buffer values until its backpressure strategy decides that the
409409
/// producer have to wait.
410410
///
411+
/// This channel is also suitable for the single-producer single-consumer use-case
411412
///
412413
/// ## Using a MultiProducerSingleConsumerChannel
413414
///
414-
/// To use a ``MultiProducerSingleConsumerChannel`` you have to create a new channel with it's source first by calling
415+
/// To use a ``MultiProducerSingleConsumerChannel`` you have to create a new channel with its source first by calling
415416
/// the ``MultiProducerSingleConsumerChannel/makeChannel(of:throwing:BackpressureStrategy:)`` method.
416417
/// Afterwards, you can pass the source to the producer and the channel to the consumer.
417418
///
418419
/// ```
419-
/// let (channel, source) = MultiProducerSingleConsumerChannel<Int, Never>.makeChannel(
420+
/// let channelAndSource = MultiProducerSingleConsumerChannel.makeChannel(
421+
/// of: Int.self,
420422
/// backpressureStrategy: .watermark(low: 2, high: 4)
421423
/// )
424+
///
425+
/// // The channel and source can be extracted from the returned type
426+
/// let channel = consume channelAndSource.channel
427+
/// let source = consume channelAndSource.source
422428
/// ```
423429
///
424-
/// ### Asynchronous producers
430+
/// ### Asynchronous producing
425431
///
426-
/// Values can be send to the source from asynchronous contexts using ``MultiProducerSingleConsumerChannel/Source/send(_:)-9b5do``
427-
/// and ``MultiProducerSingleConsumerChannel/Source/send(contentsOf:)-4myrz``. Backpressure results in calls
432+
/// Values can be send to the source from asynchronous contexts using ``MultiProducerSingleConsumerChannel/Source/send(_:)-8eo96``
433+
/// and ``MultiProducerSingleConsumerChannel/Source/send(contentsOf:)``. Backpressure results in calls
428434
/// to the `send` methods to be suspended. Once more elements should be produced the `send` methods will be resumed.
429435
///
430436
/// ```
@@ -441,10 +447,54 @@ public struct MultiProducerSingleConsumerChannelAlreadyFinishedError: Error { }
441447
/// }
442448
/// ```
443449
///
444-
/// ### Synchronous producers
450+
/// ### Synchronous produceing
445451
///
446452
/// Values can also be send to the source from synchronous context. Backpressure is also exposed on the synchronous contexts; however,
447453
/// it is up to the caller to decide how to properly translate the backpressure to underlying producer e.g. by blocking the thread.
454+
///
455+
/// ```swift
456+
/// do {
457+
/// let sendResult = try source.send(contentsOf: sequence)
458+
///
459+
/// switch sendResult {
460+
/// case .produceMore:
461+
/// // Trigger more production in the underlying system
462+
///
463+
/// case .enqueueCallback(let callbackToken):
464+
/// // There are enough values in the channel already. We need to enqueue
465+
/// // a callback to get notified when we should produce more.
466+
/// source.enqueueCallback(token: callbackToken, onProduceMore: { result in
467+
/// switch result {
468+
/// case .success:
469+
/// // Trigger more production in the underlying system
470+
/// case .failure(let error):
471+
/// // Terminate the underlying producer
472+
/// }
473+
/// })
474+
/// }
475+
/// } catch {
476+
/// // `send(contentsOf:)` throws if the channel already terminated
477+
/// }
478+
/// ```
479+
///
480+
/// ### Multiple producers
481+
///
482+
/// To support multiple producers the source offers a ``Source/copy()`` method to produce a new source.
483+
///
484+
/// ### Terminating the production of values
485+
///
486+
/// The consumer can be terminated through multiple ways:
487+
/// - Calling ``Source/finish(throwing:)``.
488+
/// - Deiniting all sources.
489+
///
490+
/// In both cases, if there are still elements buffered by the channel, then the consumer will receive
491+
/// all buffered elements. Afterwards it will be terminated.
492+
///
493+
/// ### Observing termination of the consumer
494+
///
495+
/// When the consumer stops consumption by either deiniting the channel or the task calling ``next(isolation:)``
496+
/// getting cancelled, the source will get notified about the termination if a termination callback has been set
497+
/// before by calling ``Source/setOnTerminationCallback(_:)``.
448498
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
449499
public struct MultiProducerSingleConsumerChannel<Element, Failure: Error>: ~Copyable {
450500
/// A struct containing the initialized channel and source.
@@ -783,6 +833,12 @@ has been offered with the `Continuation` based approach and
783833
introduced new factory methods to solve some of the usability ergonomics with
784834
the initializer based APIs.
785835

836+
### Provide the type on older compilers
837+
838+
To achieve maximum performance the implementation is using `~Copyable` extensively.
839+
On Swift versions before 6.1, there is a https://github.com/swiftlang/swift/issues/78048 when using; hence, this type
840+
is only usable with Swift 6.1 and later compilers.
841+
786842
## Acknowledgements
787843

788844
- [Johannes Weiss](https://github.com/weissi) - For making me aware how

Sources/AsyncAlgorithms/MultiProducerSingleConsumerChannel/MultiProducerSingleConsumerChannel+Internal.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
#if compiler(>=6.0)
12+
#if compiler(>=6.1)
1313
import DequeModule
1414
import Synchronization
1515

Sources/AsyncAlgorithms/MultiProducerSingleConsumerChannel/MultiProducerSingleConsumerChannel.swift

+58-8
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
#if compiler(>=6.0)
12+
#if compiler(>=6.1)
1313
/// An error that is thrown from the various `send` methods of the
1414
/// ``MultiProducerSingleConsumerChannel/Source``.
1515
///
@@ -20,30 +20,36 @@ public struct MultiProducerSingleConsumerChannelAlreadyFinishedError: Error {
2020
init() {}
2121
}
2222

23-
/// A multi producer single consumer channel.
23+
/// A multi-producer single-consumer channel.
2424
///
2525
/// The ``MultiProducerSingleConsumerChannel`` provides a ``MultiProducerSingleConsumerChannel/Source`` to
2626
/// send values to the channel. The channel supports different back pressure strategies to control the
2727
/// buffering and demand. The channel will buffer values until its backpressure strategy decides that the
2828
/// producer have to wait.
2929
///
30+
/// This channel is also suitable for the single-producer single-consumer use-case
3031
///
3132
/// ## Using a MultiProducerSingleConsumerChannel
3233
///
33-
/// To use a ``MultiProducerSingleConsumerChannel`` you have to create a new channel with it's source first by calling
34+
/// To use a ``MultiProducerSingleConsumerChannel`` you have to create a new channel with its source first by calling
3435
/// the ``MultiProducerSingleConsumerChannel/makeChannel(of:throwing:BackpressureStrategy:)`` method.
3536
/// Afterwards, you can pass the source to the producer and the channel to the consumer.
3637
///
3738
/// ```
38-
/// let (channel, source) = MultiProducerSingleConsumerChannel<Int, Never>.makeChannel(
39+
/// let channelAndSource = MultiProducerSingleConsumerChannel.makeChannel(
40+
/// of: Int.self,
3941
/// backpressureStrategy: .watermark(low: 2, high: 4)
4042
/// )
43+
///
44+
/// // The channel and source can be extracted from the returned type
45+
/// let channel = consume channelAndSource.channel
46+
/// let source = consume channelAndSource.source
4147
/// ```
4248
///
43-
/// ### Asynchronous producers
49+
/// ### Asynchronous producing
4450
///
45-
/// Values can be send to the source from asynchronous contexts using ``MultiProducerSingleConsumerChannel/Source/send(_:)-9b5do``
46-
/// and ``MultiProducerSingleConsumerChannel/Source/send(contentsOf:)-4myrz``. Backpressure results in calls
51+
/// Values can be send to the source from asynchronous contexts using ``MultiProducerSingleConsumerChannel/Source/send(_:)-8eo96``
52+
/// and ``MultiProducerSingleConsumerChannel/Source/send(contentsOf:)``. Backpressure results in calls
4753
/// to the `send` methods to be suspended. Once more elements should be produced the `send` methods will be resumed.
4854
///
4955
/// ```
@@ -60,10 +66,54 @@ public struct MultiProducerSingleConsumerChannelAlreadyFinishedError: Error {
6066
/// }
6167
/// ```
6268
///
63-
/// ### Synchronous producers
69+
/// ### Synchronous produceing
6470
///
6571
/// Values can also be send to the source from synchronous context. Backpressure is also exposed on the synchronous contexts; however,
6672
/// it is up to the caller to decide how to properly translate the backpressure to underlying producer e.g. by blocking the thread.
73+
///
74+
/// ```swift
75+
/// do {
76+
/// let sendResult = try source.send(contentsOf: sequence)
77+
///
78+
/// switch sendResult {
79+
/// case .produceMore:
80+
/// // Trigger more production in the underlying system
81+
///
82+
/// case .enqueueCallback(let callbackToken):
83+
/// // There are enough values in the channel already. We need to enqueue
84+
/// // a callback to get notified when we should produce more.
85+
/// source.enqueueCallback(token: callbackToken, onProduceMore: { result in
86+
/// switch result {
87+
/// case .success:
88+
/// // Trigger more production in the underlying system
89+
/// case .failure(let error):
90+
/// // Terminate the underlying producer
91+
/// }
92+
/// })
93+
/// }
94+
/// } catch {
95+
/// // `send(contentsOf:)` throws if the channel already terminated
96+
/// }
97+
/// ```
98+
///
99+
/// ### Multiple producers
100+
///
101+
/// To support multiple producers the source offers a ``Source/copy()`` method to produce a new source.
102+
///
103+
/// ### Terminating the production of values
104+
///
105+
/// The consumer can be terminated through multiple ways:
106+
/// - Calling ``Source/finish(throwing:)``.
107+
/// - Deiniting all sources.
108+
///
109+
/// In both cases, if there are still elements buffered by the channel, then the consumer will receive
110+
/// all buffered elements. Afterwards it will be terminated.
111+
///
112+
/// ### Observing termination of the consumer
113+
///
114+
/// When the consumer stops consumption by either deiniting the channel or the task calling ``next(isolation:)``
115+
/// getting cancelled, the source will get notified about the termination if a termination callback has been set
116+
/// before by calling ``Source/setOnTerminationCallback(_:)``.
67117
@available(macOS 15.0, iOS 18.0, watchOS 11.0, tvOS 18.0, visionOS 2.0, *)
68118
public struct MultiProducerSingleConsumerChannel<Element, Failure: Error>: ~Copyable {
69119
/// The backing storage.

Sources/Example/Example.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
//
1010
//===----------------------------------------------------------------------===//
1111

12-
#if compiler(>=6.0)
12+
#if compiler(>=6.1)
1313
import AsyncAlgorithms
1414

1515
@available(macOS 15.0, *)

0 commit comments

Comments
 (0)