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}