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