rune/runtime/
generator_state.rs

1use crate as rune;
2use crate::alloc::clone::TryClone;
3use crate::Any;
4
5use super::{ProtocolCaller, Value, VmError};
6
7/// The state of a generator.
8///
9/// # Examples
10///
11/// ```
12/// use rune::{Value, Vm};
13/// use rune::runtime::GeneratorState;
14/// use rune::sync::Arc;
15///
16/// let mut sources = rune::sources! {
17///     entry => {
18///         pub fn main() {
19///             let n = yield 1;
20///             let out = yield n + 1;
21///             out
22///         }
23///     }
24/// };
25///
26/// let unit = rune::prepare(&mut sources).build()?;
27/// let unit = Arc::try_new(unit)?;
28/// let mut vm = Vm::without_runtime(unit)?;
29///
30/// let mut generator = vm.execute(["main"], ())?.into_generator();
31///
32/// // Initial resume doesn't take a value.
33/// let first = match generator.resume(Value::empty())? {
34///     GeneratorState::Yielded(first) => rune::from_value::<i64>(first)?,
35///     GeneratorState::Complete(..) => panic!("generator completed"),
36/// };
37///
38/// assert_eq!(first, 1);
39///
40/// // Additional resumes require a value.
41/// let second = match generator.resume(rune::to_value(2i64)?)? {
42///     GeneratorState::Yielded(second) => rune::from_value::<i64>(second)?,
43///     GeneratorState::Complete(..) => panic!("generator completed"),
44/// };
45///
46/// assert_eq!(second, 3);
47///
48/// let ret = match generator.resume(rune::to_value(42i64)?)? {
49///     GeneratorState::Complete(ret) => rune::from_value::<i64>(ret)?,
50///     GeneratorState::Yielded(..) => panic!("generator yielded"),
51/// };
52///
53/// assert_eq!(ret, 42);
54/// # Ok::<_, rune::support::Error>(())
55/// ```
56///
57/// An asynchronous generator, also known as a stream:
58///
59/// ```
60/// use rune::{Value, Vm};
61/// use rune::sync::Arc;
62/// use rune::runtime::GeneratorState;
63///
64/// let mut sources = rune::sources! {
65///     entry => {
66///         pub async fn main() {
67///             let n = yield 1;
68///             let out = yield n + 1;
69///             out
70///         }
71///     }
72/// };
73///
74/// # futures_executor::block_on(async move {
75/// let unit = rune::prepare(&mut sources).build()?;
76/// let unit = Arc::try_new(unit)?;
77/// let mut vm = Vm::without_runtime(unit)?;
78///
79/// let mut stream = vm.execute(["main"], ())?.into_stream();
80///
81/// // Initial resume doesn't take a value.
82/// let first = match stream.resume(Value::empty()).await? {
83///     GeneratorState::Yielded(first) => rune::from_value::<i64>(first)?,
84///     GeneratorState::Complete(..) => panic!("stream completed"),
85/// };
86///
87/// assert_eq!(first, 1);
88///
89/// // Additional resumes require a value.
90/// let second = match stream.resume(rune::to_value(2i64)?).await? {
91///     GeneratorState::Yielded(second) => rune::from_value::<i64>(second)?,
92///     GeneratorState::Complete(..) => panic!("stream completed"),
93/// };
94///
95/// assert_eq!(second, 3);
96///
97/// let ret = match stream.resume(rune::to_value(42i64)?).await? {
98///     GeneratorState::Complete(ret) => rune::from_value::<i64>(ret)?,
99///     GeneratorState::Yielded(..) => panic!("stream yielded"),
100/// };
101///
102/// assert_eq!(ret, 42);
103/// # Ok::<_, rune::support::Error>(())
104/// # })?;
105/// # Ok::<_, rune::support::Error>(())
106/// ```
107#[derive(Any, Debug, TryClone)]
108#[rune(item = ::std::ops::generator)]
109pub enum GeneratorState {
110    /// The generator yielded.
111    #[rune(constructor)]
112    Yielded(#[rune(get, set)] Value),
113    /// The generator completed.
114    #[rune(constructor)]
115    Complete(#[rune(get, set)] Value),
116}
117
118impl GeneratorState {
119    /// Test if the state is yielded.
120    pub fn is_yielded(&self) -> bool {
121        matches!(self, Self::Yielded(..))
122    }
123
124    /// Test if the state is complete.
125    pub fn is_complete(&self) -> bool {
126        matches!(self, Self::Complete(..))
127    }
128
129    pub(crate) fn partial_eq_with(
130        &self,
131        other: &Self,
132        caller: &mut dyn ProtocolCaller,
133    ) -> Result<bool, VmError> {
134        match (self, other) {
135            (GeneratorState::Yielded(a), GeneratorState::Yielded(b)) => {
136                Value::partial_eq_with(a, b, caller)
137            }
138            (GeneratorState::Complete(a), GeneratorState::Complete(b)) => {
139                Value::partial_eq_with(a, b, caller)
140            }
141            _ => Ok(false),
142        }
143    }
144
145    pub(crate) fn eq_with(
146        &self,
147        other: &Self,
148        caller: &mut dyn ProtocolCaller,
149    ) -> Result<bool, VmError> {
150        match (self, other) {
151            (GeneratorState::Yielded(a), GeneratorState::Yielded(b)) => {
152                Value::eq_with(a, b, caller)
153            }
154            (GeneratorState::Complete(a), GeneratorState::Complete(b)) => {
155                Value::eq_with(a, b, caller)
156            }
157            _ => Ok(false),
158        }
159    }
160}