1use crate::pin::Pin;
2
3/// The result of a coroutine resumption.
4///
5/// This enum is returned from the `Coroutine::resume` method and indicates the
6/// possible return values of a coroutine. Currently this corresponds to either
7/// a suspension point (`Yielded`) or a termination point (`Complete`).
8#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)]
9#[lang = "coroutine_state"]
10#[unstable(feature = "coroutine_trait", issue = "43122")]
11pub enum CoroutineState<Y, R> {
12 /// The coroutine suspended with a value.
13 ///
14 /// This state indicates that a coroutine has been suspended, and typically
15 /// corresponds to a `yield` statement. The value provided in this variant
16 /// corresponds to the expression passed to `yield` and allows coroutines to
17 /// provide a value each time they yield.
18 Yielded(Y),
19
20 /// The coroutine completed with a return value.
21 ///
22 /// This state indicates that a coroutine has finished execution with the
23 /// provided value. Once a coroutine has returned `Complete` it is
24 /// considered a programmer error to call `resume` again.
25 Complete(R),
26}
27
28/// The trait implemented by builtin coroutine types.
29///
30/// Coroutines are currently an
31/// experimental language feature in Rust. Added in [RFC 2033] coroutines are
32/// currently intended to primarily provide a building block for async/await
33/// syntax but will likely extend to also providing an ergonomic definition for
34/// iterators and other primitives.
35///
36/// The syntax and semantics for coroutines is unstable and will require a
37/// further RFC for stabilization. At this time, though, the syntax is
38/// closure-like:
39///
40/// ```rust
41/// #![feature(coroutines)]
42/// #![feature(coroutine_trait)]
43///
44/// use std::ops::{Coroutine, CoroutineState};
45/// use std::pin::Pin;
46///
47/// fn main() {
48/// let mut coroutine = || {
49/// yield 1;
50/// "foo"
51/// };
52///
53/// match Pin::new(&mut coroutine).resume(()) {
54/// CoroutineState::Yielded(1) => {}
55/// _ => panic!("unexpected return from resume"),
56/// }
57/// match Pin::new(&mut coroutine).resume(()) {
58/// CoroutineState::Complete("foo") => {}
59/// _ => panic!("unexpected return from resume"),
60/// }
61/// }
62/// ```
63///
64/// More documentation of coroutines can be found in the [unstable book].
65///
66/// [RFC 2033]: https://github.com/rust-lang/rfcs/pull/2033
67/// [unstable book]: ../../unstable-book/language-features/coroutines.html
68#[lang = "coroutine"]
69#[unstable(feature = "coroutine_trait", issue = "43122")]
70#[fundamental]
71pub trait Coroutine<R = ()> {
72 /// The type of value this coroutine yields.
73 ///
74 /// This associated type corresponds to the `yield` expression and the
75 /// values which are allowed to be returned each time a coroutine yields.
76 /// For example an iterator-as-a-coroutine would likely have this type as
77 /// `T`, the type being iterated over.
78 type Yield;
79
80 /// The type of value this coroutine returns.
81 ///
82 /// This corresponds to the type returned from a coroutine either with a
83 /// `return` statement or implicitly as the last expression of a coroutine
84 /// literal. For example futures would use this as `Result<T, E>` as it
85 /// represents a completed future.
86 type Return;
87
88 /// Resumes the execution of this coroutine.
89 ///
90 /// This function will resume execution of the coroutine or start execution
91 /// if it hasn't already. This call will return back into the coroutine's
92 /// last suspension point, resuming execution from the latest `yield`. The
93 /// coroutine will continue executing until it either yields or returns, at
94 /// which point this function will return.
95 ///
96 /// # Return value
97 ///
98 /// The `CoroutineState` enum returned from this function indicates what
99 /// state the coroutine is in upon returning. If the `Yielded` variant is
100 /// returned then the coroutine has reached a suspension point and a value
101 /// has been yielded out. Coroutines in this state are available for
102 /// resumption at a later point.
103 ///
104 /// If `Complete` is returned then the coroutine has completely finished
105 /// with the value provided. It is invalid for the coroutine to be resumed
106 /// again.
107 ///
108 /// # Panics
109 ///
110 /// This function may panic if it is called after the `Complete` variant has
111 /// been returned previously. While coroutine literals in the language are
112 /// guaranteed to panic on resuming after `Complete`, this is not guaranteed
113 /// for all implementations of the `Coroutine` trait.
114 #[cfg_attr(not(bootstrap), lang = "coroutine_resume")]
115 fn resume(self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return>;
116}
117
118#[unstable(feature = "coroutine_trait", issue = "43122")]
119impl<G: ?Sized + Coroutine<R>, R> Coroutine<R> for Pin<&mut G> {
120 type Yield = G::Yield;
121 type Return = G::Return;
122
123 fn resume(mut self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
124 G::resume((*self).as_mut(), arg)
125 }
126}
127
128#[unstable(feature = "coroutine_trait", issue = "43122")]
129impl<G: ?Sized + Coroutine<R> + Unpin, R> Coroutine<R> for &mut G {
130 type Yield = G::Yield;
131 type Return = G::Return;
132
133 fn resume(mut self: Pin<&mut Self>, arg: R) -> CoroutineState<Self::Yield, Self::Return> {
134 G::resume(self:Pin::new(&mut *self), arg)
135 }
136}
137