1use std::any::Any;
6use std::mem::MaybeUninit;
7use std::ptr;
8
9use crate::reg_context::RegContext;
10
11thread_local!(
12 static ROOT_CONTEXT: Box<Context> = {
14 let mut root = Box::new(Context::new());
15 let p = &mut *root as *mut _;
16 root.parent = p; root
18 }
19);
20
21#[cfg(nightly)]
26#[thread_local]
27static mut ROOT_CONTEXT_P: *mut Context = ptr::null_mut();
28
29#[allow(dead_code)]
31#[derive(Debug, Copy, Clone, Eq, PartialEq)]
32pub enum Error {
33 Cancel,
35 TypeErr,
37 StackErr,
39 ContextErr,
41}
42
43#[repr(C)]
45pub struct Context {
46 pub regs: RegContext,
48 child: *mut Context,
50 pub parent: *mut Context,
52 pub para: MaybeUninit<*mut dyn Any>,
54 pub ret: MaybeUninit<*mut dyn Any>,
56 pub _ref: usize,
58 pub local_data: *mut u8,
60 pub err: Option<Box<dyn Any + Send>>,
62}
63
64impl Context {
65 pub fn new() -> Context {
67 Context {
68 regs: RegContext::empty(),
69 para: MaybeUninit::zeroed(),
70 ret: MaybeUninit::zeroed(),
71 _ref: 1, err: None,
73 child: ptr::null_mut(),
74 parent: ptr::null_mut(),
75 local_data: ptr::null_mut(),
76 }
77 }
78
79 #[inline]
81 pub fn is_generator(&self) -> bool {
82 self.parent != self as *const _ as *mut _
83 }
84
85 #[inline]
87 pub fn get_para<A>(&mut self) -> Option<A>
88 where
89 A: Any,
90 {
91 let para = unsafe {
92 let para_ptr = *self.para.as_mut_ptr();
93 assert!(!para_ptr.is_null());
94 &mut *para_ptr
95 };
96 match para.downcast_mut::<Option<A>>() {
97 Some(v) => v.take(),
98 None => type_error::<A>("get yield type mismatch error detected"),
99 }
100 }
101
102 #[inline]
104 pub fn co_get_para<A>(&mut self) -> Option<A> {
105 let para = unsafe {
106 let para_ptr = *self.para.as_mut_ptr();
107 debug_assert!(!para_ptr.is_null());
108 &mut *(para_ptr as *mut Option<A>)
109 };
110 para.take()
111 }
112
113 #[inline]
116 pub fn co_set_para<A>(&mut self, data: A) {
117 let para = unsafe {
118 let para_ptr = *self.para.as_mut_ptr();
119 debug_assert!(!para_ptr.is_null());
120 &mut *(para_ptr as *mut Option<A>)
121 };
122 *para = Some(data);
123 }
124
125 #[inline]
127 pub fn set_ret<T>(&mut self, v: T)
128 where
129 T: Any,
130 {
131 let ret = unsafe {
132 let ret_ptr = *self.ret.as_mut_ptr();
133 assert!(!ret_ptr.is_null());
134 &mut *ret_ptr
135 };
136 match ret.downcast_mut::<Option<T>>() {
137 Some(r) => *r = Some(v),
138 None => type_error::<T>("yield type mismatch error detected"),
139 }
140 }
141
142 #[inline]
145 pub fn co_set_ret<T>(&mut self, v: T) {
146 let ret = unsafe {
147 let ret_ptr = *self.ret.as_mut_ptr();
148 debug_assert!(!ret_ptr.is_null());
149 &mut *(ret_ptr as *mut Option<T>)
150 };
151 *ret = Some(v);
152 }
153}
154
155pub struct ContextStack {
157 root: *mut Context,
158}
159
160#[cfg(nightly)]
161#[inline(never)]
162unsafe fn init_root_p() {
163 ROOT_CONTEXT_P = ROOT_CONTEXT.with(|r| &**r as *const _ as *mut Context);
164}
165
166impl ContextStack {
167 #[cfg(nightly)]
168 #[inline(never)]
169 pub fn current() -> ContextStack {
170 unsafe {
171 if ROOT_CONTEXT_P.is_null() {
172 init_root_p();
173 }
174 ContextStack {
175 root: ROOT_CONTEXT_P,
176 }
177 }
178 }
179
180 #[cfg(not(nightly))]
181 #[inline(never)]
182 pub fn current() -> ContextStack {
183 let root = ROOT_CONTEXT.with(|r| &**r as *const _ as *mut Context);
184 ContextStack { root }
185 }
186
187 #[inline]
189 pub fn top(&self) -> &'static mut Context {
190 let root = unsafe { &mut *self.root };
191 unsafe { &mut *root.parent }
192 }
193
194 #[inline]
196 pub fn co_ctx(&self) -> Option<&'static mut Context> {
197 let root = unsafe { &mut *self.root };
198
199 let mut ctx = unsafe { &mut *root.parent };
201 while ctx as *const _ != root as *const _ {
202 if !ctx.local_data.is_null() {
203 return Some(ctx);
204 }
205 ctx = unsafe { &mut *ctx.parent };
206 }
207 None
209 }
210
211 #[inline]
213 pub fn push_context(&self, ctx: *mut Context) {
214 let root = unsafe { &mut *self.root };
215 let ctx = unsafe { &mut *ctx };
216 let top = unsafe { &mut *root.parent };
217 let new_top = ctx.parent;
218
219 top.child = ctx;
221 ctx.parent = top;
222
223 root.parent = new_top;
225 }
226
227 #[inline]
229 pub fn pop_context(&self, ctx: *mut Context) -> &'static mut Context {
230 let root = unsafe { &mut *self.root };
231 let ctx = unsafe { &mut *ctx };
232 let parent = unsafe { &mut *ctx.parent };
233
234 ctx.parent = root.parent;
236 parent.child = ptr::null_mut();
238
239 root.parent = parent;
241
242 parent
243 }
244}
245
246#[inline]
247fn type_error<A>(msg: &str) -> ! {
248 #[cfg(nightly)]
249 #[allow(unused_unsafe)]
250 {
251 use std::intrinsics::type_name;
252 let t = unsafe { type_name::<A>() };
253 error!("{}, expected type: {}", msg, t);
254 }
255
256 #[cfg(not(nightly))]
257 {
258 error!("{}", msg);
259 }
260 std::panic::panic_any(Error::TypeErr)
261}
262
263#[inline]
265pub fn is_generator() -> bool {
266 let env = ContextStack::current();
267 let root = unsafe { &mut *env.root };
268 !root.child.is_null()
269}
270
271#[inline]
274pub fn get_local_data() -> *mut u8 {
275 let env = ContextStack::current();
276 let root = unsafe { &mut *env.root };
277
278 let mut ctx = unsafe { &mut *root.parent };
280 while ctx as *const _ != root as *const _ {
281 if !ctx.local_data.is_null() {
282 return ctx.local_data;
283 }
284 ctx = unsafe { &mut *ctx.parent };
285 }
286
287 ptr::null_mut()
288}
289
290#[cfg(test)]
291mod test {
292 use super::is_generator;
293
294 #[test]
295 fn test_is_context() {
296 assert!(!is_generator());
298 }
299}