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};
8use anyhow::Context;
9// use tramp::{tramp, BorrowRec, Thunk};
10pub 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    // let go: Df<A, B, C> = cast(go);
112    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}