wars_rt/
func.rs

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