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