wars_rt/
func.rs

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