1use alloc::vec;
2use alloc::{boxed::Box, sync::Arc, vec::Vec};
3use core::{
4 future::Future,
5 iter::{empty, once},
6 pin::Pin,
7};
8use anyhow::Context;
9pub fn ret<'a, T>(a: T) -> AsyncRec<'a, T> {
11 AsyncRec::Ret(a)
12}
13pub enum AsyncRec<'a, T> {
14 Ret(T),
15 Async(Pin<Box<dyn UnwrappedAsyncRec<'a, T>>>),
16}
17pub trait UnwrappedAsyncRec<'a, T>: Future<Output = AsyncRec<'a, T>> + Send + Sync + 'a {
18 async fn go(mut self) -> T
19 where
20 Self: Sized,
21 {
22 return self.await.go().await;
23 }
24}
25pub trait Wrap<'a,T>: Sized{
26 fn wrap(self) -> AsyncRec<'a,T>;
27}
28impl<'a,T> Wrap<'a,T> for AsyncRec<'a,T>{
29 fn wrap(self) -> AsyncRec<'a,T> {
30 self
31 }
32}
33impl<'a,T,F: UnwrappedAsyncRec<'a,T>> Wrap<'a,T> for F{
34 fn wrap(self) -> AsyncRec<'a,T> {
35 AsyncRec::Async(Box::pin(self))
36 }
37}
38impl<'a, T, F: Future<Output = AsyncRec<'a, T>> + Send + Sync + 'a> UnwrappedAsyncRec<'a, T> for F {}
39impl<'a, T> AsyncRec<'a, T> {
40 pub fn wrap(x: impl Wrap<'a,T>) -> Self{
41 x.wrap()
42 }
43 pub async fn go(mut self) -> T {
44 loop {
45 self = match self {
46 AsyncRec::Ret(r) => return r,
47 AsyncRec::Async(a) => a.await,
48 }
49 }
50 }
51}
52pub use crate::CtxSpec;
53use crate::Traverse;
54#[non_exhaustive]
55pub enum Value<C: CtxSpec> {
56 I32(u32),
57 I64(u64),
58 F32(f32),
59 F64(f64),
60 FunRef(
61 Arc<
62 dyn for<'a> Fn(&'a mut C, Vec<Value<C>>) -> AsyncRec<'a, anyhow::Result<Vec<Value<C>>>>
63 + Send
64 + Sync
65 + 'static,
66 >,
67 ),
68 Null,
69 ExRef(C::ExternRef),
70 #[cfg(feature = "dumpster")]
71 Gc(crate::gc::GcCore<Value<C>>),
72}
73#[cfg(feature = "dumpster")]
74const _: () = {
75 use dumpster::Trace;
76 unsafe impl<C: CtxSpec<ExternRef: Trace>> Trace for Value<C> {
77 fn accept<V: dumpster::Visitor>(&self, visitor: &mut V) -> Result<(), ()> {
78 match self {
79 Self::ExRef(e) => e.accept(visitor),
80 Self::Gc(g) => g.accept(visitor),
81 _ => Ok(()),
82 }
83 }
84 }
85};
86impl<C: CtxSpec> Traverse<C> for Value<C> {
87 fn traverse<'a>(&'a self) -> Box<dyn Iterator<Item = &'a <C as CtxSpec>::ExternRef> + 'a> {
88 match self {
89 Value::ExRef(e) => Box::new(once(e)),
90 #[cfg(feature = "dumpster")]
91 Value::Gc(g) => g.traverse(),
92 _ => Box::new(empty()),
93 }
94 }
95 fn traverse_mut<'a>(
96 &'a mut self,
97 ) -> Box<dyn Iterator<Item = &'a mut <C as CtxSpec>::ExternRef> + 'a> {
98 match self {
99 Value::ExRef(e) => Box::new(once(e)),
100 #[cfg(feature = "dumpster")]
101 Value::Gc(g) => g.traverse_mut(),
102 _ => Box::new(empty()),
103 }
104 }
105}
106pub fn call_ref<'a, A: CoeVec<C> + 'static, B: CoeVec<C> + 'static, C: CtxSpec + 'static>(
107 ctx: &'a mut C,
108 go: Df<A, B, C>,
109 a: A,
110) -> AsyncRec<'a, anyhow::Result<B>> {
111 go(ctx, a)
113}
114impl<C: CtxSpec> Clone for Value<C> {
115 fn clone(&self) -> Self {
116 match self {
117 Self::I32(arg0) => Self::I32(arg0.clone()),
118 Self::I64(arg0) => Self::I64(arg0.clone()),
119 Self::F32(arg0) => Self::F32(arg0.clone()),
120 Self::F64(arg0) => Self::F64(arg0.clone()),
121 Self::FunRef(arg0) => Self::FunRef(arg0.clone()),
122 Self::Null => Self::Null,
123 Self::ExRef(e) => Self::ExRef(e.clone()),
124 #[cfg(feature = "dumpster")]
125 Self::Gc(c) => Self::Gc(c.clone()),
126 }
127 }
128}
129pub trait Coe<C: CtxSpec>: Sized {
130 fn coe(self) -> Value<C>;
131 fn uncoe(x: Value<C>) -> anyhow::Result<Self>;
132}
133pub fn cast<A: Coe<C> + 'static, B: Coe<C> + 'static, C: CtxSpec>(a: A) -> B {
134 let a = match castaway::cast!(a, B) {
135 Ok(b) => return b,
136 Err(a) => a,
137 };
138 B::uncoe(A::coe(a)).unwrap()
139}
140impl<C: CtxSpec> Coe<C> for Value<C> {
141 fn coe(self) -> Value<C> {
142 self
143 }
144 fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
145 Ok(x)
146 }
147}
148impl<C: CtxSpec, D: Coe<C>> Coe<C> for Option<D> {
149 fn coe(self) -> Value<C> {
150 match self {
151 None => Value::Null,
152 Some(d) => d.coe(),
153 }
154 }
155 fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
156 if let Value::Null = x {
157 return Ok(None);
158 }
159 return Ok(Some(D::uncoe(x)?));
160 }
161}
162macro_rules! coe_impl_prim {
163 ($a:tt in $b:ident) => {
164 impl<C: CtxSpec> Coe<C> for $a {
165 fn coe(self) -> Value<C> {
166 Value::$b(self)
167 }
168 fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
169 match x {
170 Value::$b(a) => Ok(a),
171 _ => anyhow::bail!("invalid type"),
172 }
173 }
174 }
175 };
176}
177coe_impl_prim!(u32 in I32);
178coe_impl_prim!(u64 in I64);
179coe_impl_prim!(f32 in F32);
180coe_impl_prim!(f64 in F64);
181#[cfg(feature = "dumpster")]
182pub trait CoeField<C: CtxSpec>: Sized {
183 fn coe(self) -> crate::gc::Field<Value<C>>;
184 fn uncoe(x: crate::gc::Field<Value<C>>) -> anyhow::Result<Self>;
185}
186#[cfg(feature = "dumpster")]
187pub trait CoeFieldVec<C: CtxSpec>: Sized {
188 const NUM: usize;
189 fn coe(self) -> Vec<crate::gc::Field<Value<C>>>;
190 fn uncoe(a: Vec<crate::gc::Field<Value<C>>>) -> anyhow::Result<Self>;
191}
192#[cfg(feature = "dumpster")]
193const _: () = {
194 use std::sync::Mutex;
195 use crate::gc::{Const, Field, Mut, Struct};
196 impl<C: CtxSpec, V: Coe<C>> CoeField<C> for Const<V> {
197 fn coe(self) -> crate::gc::Field<Value<C>> {
198 crate::gc::Field::Const(self.0.coe())
199 }
200 fn uncoe(x: crate::gc::Field<Value<C>>) -> anyhow::Result<Self> {
201 V::uncoe(match x {
202 crate::gc::Field::Const(a) => a,
203 crate::gc::Field::Mut(arc) => arc.lock().unwrap().clone(),
204 })
205 .map(Self)
206 }
207 }
208 impl<C: CtxSpec, V: Coe<C>> CoeField<C> for Mut<V> {
209 fn coe(self) -> crate::gc::Field<Value<C>> {
210 crate::gc::Field::Mut(Arc::new(Mutex::new(self.0.coe())))
211 }
212 fn uncoe(x: crate::gc::Field<Value<C>>) -> anyhow::Result<Self> {
213 V::uncoe(match x {
214 crate::gc::Field::Const(a) => a,
215 crate::gc::Field::Mut(arc) => arc.lock().unwrap().clone(),
216 })
217 .map(Self)
218 }
219 }
220 impl<C: CtxSpec> CoeFieldVec<C> for () {
221 fn coe(self) -> Vec<Field<Value<C>>> {
222 vec![]
223 }
224 fn uncoe(a: Vec<Field<Value<C>>>) -> anyhow::Result<Self> {
225 Ok(())
226 }
227 const NUM: usize = 0;
228 }
229 impl<C: CtxSpec, A: CoeField<C>, B: CoeFieldVec<C>> CoeFieldVec<C> for (A, B) {
230 fn coe(self) -> Vec<Field<Value<C>>> {
231 let mut a = self.1.coe();
232 a.push(self.0.coe());
233 return a;
234 }
235 fn uncoe(mut a: Vec<Field<Value<C>>>) -> anyhow::Result<Self> {
236 let Some(x) = a.pop() else {
237 anyhow::bail!("list too small")
238 };
239 let y = A::uncoe(x).context("invalid item (note coe lists are REVERSED)")?;
240 let z = B::uncoe(a)?;
241 Ok((y, z))
242 }
243 const NUM: usize = B::NUM + 1;
244 }
245 impl<C: CtxSpec, V: CoeFieldVec<C>> Coe<C> for Struct<V> {
246 fn coe(self) -> Value<C> {
247 Value::Gc(crate::gc::GcCore::Fields(self.0.coe()))
248 }
249 fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
250 match x {
251 Value::Gc(crate::gc::GcCore::Fields(f)) => V::uncoe(f).map(Self),
252 _ => anyhow::bail!("nota gc"),
253 }
254 }
255 }
256};
257pub trait CoeVec<C: CtxSpec>: Sized {
258 const NUM: usize;
259 fn coe(self) -> Vec<Value<C>>;
260 fn uncoe(a: Vec<Value<C>>) -> anyhow::Result<Self>;
261}
262impl<C: CtxSpec> CoeVec<C> for () {
263 fn coe(self) -> Vec<Value<C>> {
264 vec![]
265 }
266 fn uncoe(a: Vec<Value<C>>) -> anyhow::Result<Self> {
267 Ok(())
268 }
269 const NUM: usize = 0;
270}
271impl<C: CtxSpec, A: Coe<C>, B: CoeVec<C>> CoeVec<C> for (A, B) {
272 fn coe(self) -> Vec<Value<C>> {
273 let mut a = self.1.coe();
274 a.push(self.0.coe());
275 return a;
276 }
277 fn uncoe(mut a: Vec<Value<C>>) -> anyhow::Result<Self> {
278 let Some(x) = a.pop() else {
279 anyhow::bail!("list too small")
280 };
281 let y = A::uncoe(x).context("invalid item (note coe lists are REVERSED)")?;
282 let z = B::uncoe(a)?;
283 Ok((y, z))
284 }
285 const NUM: usize = B::NUM + 1;
286}
287pub fn map_rec<'a, T: 'a, U>(
288 r: AsyncRec<'a, T>,
289 go: impl FnOnce(T) -> U + Send + Sync + 'a,
290) -> AsyncRec<'a, U> {
291 match r {
292 AsyncRec::Ret(x) => AsyncRec::Ret(go(x)),
293 AsyncRec::Async(a) => AsyncRec::Async(Box::pin(async move {
294 let v = a.await;
295 map_rec(v, go)
296 })),
297 }
298}
299pub type Df<A, B, C> =
300 Arc<dyn for<'a> Fn(&'a mut C, A) -> AsyncRec<'a, anyhow::Result<B>> + Send + Sync + 'static>;
301pub fn da<
302 A,
303 B,
304 C,
305 F: for<'a> Fn(&'a mut C, A) -> AsyncRec<'a, anyhow::Result<B>> + Send + Sync + 'static,
306>(
307 f: F,
308) -> Df<A, B, C> {
309 Arc::new(f)
310}
311impl<C: CtxSpec + 'static, A: CoeVec<C> + 'static, B: CoeVec<C> + 'static> Coe<C> for Df<A, B, C> {
312 fn coe(self) -> Value<C> {
313 pub fn x<
314 C: CtxSpec,
315 T: for<'a> Fn(&'a mut C, Vec<Value<C>>) -> AsyncRec<'a, anyhow::Result<Vec<Value<C>>>>
316 + 'static,
317 >(
318 a: T,
319 ) -> T {
320 return a;
321 }
322 Value::FunRef(Arc::new(x(move |ctx, x| {
323 let x = match A::uncoe(x) {
324 Ok(x) => x,
325 Err(e) => return AsyncRec::Ret(Err(e)),
326 };
327 let x = self(ctx, x);
328 map_rec(x, |a| a.map(|b| b.coe()))
329 })))
330 }
331 fn uncoe(x: Value<C>) -> anyhow::Result<Self> {
332 let Value::FunRef(x) = x else {
333 anyhow::bail!("invalid value")
334 };
335 Ok(Arc::new(move |ctx, a| {
336 let v = a.coe();
337 let v = x(ctx, v);
338 map_rec(v, |a| a.and_then(B::uncoe))
339 }))
340 }
341}