1use alloc::boxed::Box;
2use core::iter::{empty, once};
3use 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 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}