wars_rt/func/
unsync.rs

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