rune/runtime/
generator.rs
1use core::fmt;
2use core::iter;
3
4use crate as rune;
5use crate::alloc::clone::TryClone;
6use crate::runtime::{GeneratorState, Value, Vm, VmError, VmErrorKind, VmExecution, VmResult};
7use crate::Any;
8
9#[derive(Any)]
28#[rune(crate, impl_params = [Vm], item = ::std::ops::generator)]
29pub struct Generator<T = Vm>
30where
31 T: AsRef<Vm> + AsMut<Vm>,
32{
33 execution: Option<VmExecution<T>>,
34}
35
36impl<T> Generator<T>
37where
38 T: AsRef<Vm> + AsMut<Vm>,
39{
40 pub(crate) fn new(vm: T) -> Self {
42 Self {
43 execution: Some(VmExecution::new(vm)),
44 }
45 }
46
47 pub(crate) fn from_execution(execution: VmExecution<T>) -> Self {
49 Self {
50 execution: Some(execution),
51 }
52 }
53
54 #[allow(clippy::should_implement_trait)]
56 pub fn next(&mut self) -> VmResult<Option<Value>> {
57 let Some(execution) = self.execution.as_mut() else {
58 return VmResult::Ok(None);
59 };
60
61 let state = if execution.is_resumed() {
62 vm_try!(execution.resume_with(Value::empty()))
63 } else {
64 vm_try!(execution.resume())
65 };
66
67 VmResult::Ok(match state {
68 GeneratorState::Yielded(value) => Some(value),
69 GeneratorState::Complete(_) => {
70 self.execution = None;
71 None
72 }
73 })
74 }
75
76 pub fn resume(&mut self, value: Value) -> VmResult<GeneratorState> {
78 let execution = vm_try!(self
79 .execution
80 .as_mut()
81 .ok_or(VmErrorKind::GeneratorComplete));
82
83 let state = if execution.is_resumed() {
84 vm_try!(execution.resume_with(value))
85 } else {
86 vm_try!(execution.resume())
87 };
88
89 if state.is_complete() {
90 self.execution = None;
91 }
92
93 VmResult::Ok(state)
94 }
95}
96
97impl Generator<&mut Vm> {
98 pub fn into_owned(self) -> Generator<Vm> {
100 Generator {
101 execution: self.execution.map(|e| e.into_owned()),
102 }
103 }
104}
105
106impl Generator {
107 pub fn rune_iter(self) -> Iter {
109 self.into_iter()
110 }
111}
112
113impl IntoIterator for Generator {
114 type Item = Result<Value, VmError>;
115 type IntoIter = Iter;
116
117 #[inline]
118 fn into_iter(self) -> Self::IntoIter {
119 Iter { generator: self }
120 }
121}
122
123#[derive(Any)]
124#[rune(item = ::std::ops::generator)]
125pub struct Iter {
126 generator: Generator,
127}
128
129impl Iter {
130 #[rune::function(instance, keep, protocol = NEXT)]
131 pub(crate) fn next(&mut self) -> VmResult<Option<Value>> {
132 self.generator.next()
133 }
134}
135
136impl iter::Iterator for Iter {
137 type Item = Result<Value, VmError>;
138
139 #[inline]
140 fn next(&mut self) -> Option<Result<Value, VmError>> {
141 match Iter::next(self) {
142 VmResult::Ok(Some(value)) => Some(Ok(value)),
143 VmResult::Ok(None) => None,
144 VmResult::Err(error) => Some(Err(error)),
145 }
146 }
147}
148
149impl<T> fmt::Debug for Generator<T>
150where
151 T: AsRef<Vm> + AsMut<Vm>,
152{
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 f.debug_struct("Generator")
155 .field("completed", &self.execution.is_none())
156 .finish()
157 }
158}
159
160impl<T> TryClone for Generator<T>
161where
162 T: TryClone + AsRef<Vm> + AsMut<Vm>,
163{
164 #[inline]
165 fn try_clone(&self) -> Result<Self, rune_alloc::Error> {
166 Ok(Self {
167 execution: self.execution.try_clone()?,
168 })
169 }
170}