1pub enum GeneratorState {
5 Ready,
7 Yielded(Box<dyn std::any::Any>),
10 Complete(Box<dyn std::any::Any>),
14}
15
16impl Default for GeneratorState {
17 fn default() -> Self {
18 Self::Ready
19 }
20}
21
22use crate::ctx::*;
23use crate::ptr::*;
24use crate::scheduler::*;
25
26pub struct Generator {
27 pub state: Ptr<GeneratorState>,
28 pub(crate) complete: std::cell::Cell<bool>,
29 pub thread: Ptr<Context>,
30 pub to: Ptr<Context>,
31 pub is_join: bool,
32}
33
34use std::rc::Rc;
35
36impl Generator {
37 pub fn spawn<F: 'static, A: 'static + crate::ctx::ApplyTo<F> + Clone>(
39 closure: F,
40 args: A,
41 ) -> Rc<Self> {
42 crate::scheduler::RUNTIME.with(|rt| {
43 let to = rt.active_ctx;
44 let thread = rt.get().spawn_not_schedule(closure, args).thread();
45
46 let generator = Rc::new(Generator {
47 state: Ptr::new(GeneratorState::Ready),
48 thread,
49 to,
50 complete: std::cell::Cell::new(false),
51 is_join: false,
52 });
53 thread.get().generator = Some(generator.clone());
54 generator
55 })
56 }
57
58 pub fn resume(&self) -> Result<GeneratorState, &'static str> {
63 if self.complete.get() {
64 return Err("Generator already complete");
65 }
66 RUNTIME.with(|rt| {
67 rt.get().resume(self.thread);
68 rt.get().switch_without_current();
69 });
70 if let GeneratorState::Complete(_) = &self.state.get() {
71 self.complete.set(true);
72 }
73 let state = self.state.take();
74 Ok(state)
75 }
76}
77
78pub fn generator_yield<T: 'static>(val: T) -> Result<(), &'static str> {
80 crate::scheduler::RUNTIME.with(|rt| rt.get().t_yield_generator(val))
81}
82
83#[macro_export]
85macro_rules! iterate_generator {
86 (for ($x: ident in $generator: expr) $b: block) => {
87 loop {
88 match $generator.resume() {
89 Ok(greenie::generator::GeneratorState::Yielded($x)) => $b,
90 Ok(greenie::generator::GeneratorState::Complete($x)) => {
91 break $x
92 },
93 Err(e) => {
94 eprintln!("{}",e);
95 std::process::exit(1);
96 }
97 _ => panic!("Unexpected")
98 }
99 }
100 };
101 (for ($x: ident in $generator: expr) $b: block and $b2: block) => {
102 loop {
103 match $generator.resume() {
104 Ok(greenie::generator::GeneratorState::Yielded($x)) => $b,
105 Ok(greenie::generator::GeneratorState::Complete($x)) => {
106 $b2
107 break;
108 },
109 Ok(GeneratorState::Ready) => panic!("impossible"),
110 Err(e) => {
111 eprintln!("{}",e);
112 std::process::exit(1);
113 }
114 _ => unreachable!()
115 }
116 }
117 };
118
119 (enumerate for ($c: ident, $x: ident in $generator: expr) $b: block) => {
120 let mut $c = 0;
121 loop {
122 match $generator.resume() {
123 Ok(greenie::generator::GeneratorState::Yielded($x)) => $b,
124 Ok(greenie::generator::GeneratorState::Complete($x)) => {
125 break $x
126 },
127 Err(e) => {
128 eprintln!("{}",e);
129 std::process::exit(1);
130 }
131 _ => unreachable!()
132 }
133 $c += 1;
134 }
135 };
136
137 (enumerate for ($c: ident, $x: ident in $generator: expr) $b: block and $b2: block) => {
138 let mut $c = 0;
139 loop {
140 match $generator.resume() {
141 Ok(greenie::generator::GeneratorState::Yielded($x)) => $b,
142 Ok(greenie::generator::GeneratorState::Complete($x)) => {
143 $b2
144 break;
145 },
146 Ok(greenie::generator::GeneratorState::Ready) => panic!("impossible"),
147 Err(e) => {
148 eprintln!("{}",e);
149 std::process::exit(1);
150 }
151 _ => unreachable!()
152 }
153 $c += 1;
154 }
155 };
156}