1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
use super::*; pub struct Generator { code: Rc<Code>, frame: Frame, } impl Generator { pub(crate) fn new(code: Rc<Code>, frame: Frame) -> Self { Self { code, frame } } pub fn resume(&mut self, globals: &mut Globals, arg: Value) -> ResumeResult { self.code.resume_frame(globals, &mut self.frame, arg) } pub fn unpack(&mut self, globals: &mut Globals) -> Result<Vec<Value>> { let mut ret = Vec::new(); loop { match self.resume(globals, Value::Nil) { ResumeResult::Yield(value) => ret.push(value), ResumeResult::Return(_) => break, ResumeResult::Err(error) => return Err(error), } } Ok(ret) } pub fn iter<'a>( &'a mut self, globals: &'a mut Globals, ) -> impl Iterator<Item = Result<Value>> + 'a { geniter(self, globals) } } impl cmp::PartialEq for Generator { fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } } impl cmp::PartialOrd for Generator { fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { (self as *const Self as usize).partial_cmp(&(other as *const Self as usize)) } } impl fmt::Debug for Generator { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "<generator object {} at {:?}>", self.code.name(), self as *const _ ) } } pub struct NativeGenerator { name: Cow<'static, str>, body: Box<dyn FnMut(&mut Globals, Value) -> ResumeResult>, } impl NativeGenerator { pub fn new<B>(name: &'static str, body: B) -> Self where B: FnMut(&mut Globals, Value) -> ResumeResult + 'static, { Self { name: Cow::Borrowed(name), body: Box::new(body), } } pub fn new_with_dynamic_name<N, B>(name: N, body: B) -> Self where N: Into<String>, B: FnMut(&mut Globals, Value) -> ResumeResult + 'static, { Self { name: Cow::Owned(name.into()), body: Box::new(body), } } pub fn name(&self) -> &str { match &self.name { Cow::Borrowed(s) => s, Cow::Owned(s) => s, } } pub fn resume(&mut self, globals: &mut Globals, arg: Value) -> ResumeResult { (self.body)(globals, arg) } pub fn unpack(&mut self, globals: &mut Globals) -> Result<Vec<Value>> { let mut ret = Vec::new(); loop { match self.resume(globals, Value::Nil) { ResumeResult::Yield(value) => ret.push(value), ResumeResult::Return(_) => break, ResumeResult::Err(error) => return Err(error), } } Ok(ret) } pub fn iter<'a>( &'a mut self, globals: &'a mut Globals, ) -> impl Iterator<Item = Result<Value>> + 'a { geniter(self, globals) } } impl cmp::PartialEq for NativeGenerator { fn eq(&self, other: &Self) -> bool { self as *const _ == other as *const _ } } impl cmp::PartialOrd for NativeGenerator { fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> { (self as *const Self as usize).partial_cmp(&(other as *const Self as usize)) } } impl fmt::Debug for NativeGenerator { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "<native generator object {} at {:?}>", self.name, self as *const _ ) } } pub enum ResumeResult { Yield(Value), Return(Value), Err(Error), } trait BaseGenerator { fn resume(&mut self, globals: &mut Globals, arg: Value) -> ResumeResult; } fn geniter<'a, G: BaseGenerator>( gen: &'a mut G, globals: &'a mut Globals, ) -> impl Iterator<Item = Result<Value>> + 'a { struct Iter<'a, G: BaseGenerator> { gen: &'a mut G, gl: &'a mut Globals, } impl<'a, G: BaseGenerator> Iterator for Iter<'a, G> { type Item = Result<Value>; fn next(&mut self) -> Option<Result<Value>> { match self.gen.resume(self.gl, Value::Nil) { ResumeResult::Yield(value) => Some(Ok(value)), ResumeResult::Return(_) => None, ResumeResult::Err(error) => Some(Err(error)), } } } Iter { gen, gl: globals } } impl BaseGenerator for Generator { fn resume(&mut self, globals: &mut Globals, arg: Value) -> ResumeResult { self.resume(globals, arg) } } impl BaseGenerator for NativeGenerator { fn resume(&mut self, globals: &mut Globals, arg: Value) -> ResumeResult { self.resume(globals, arg) } }