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