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