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