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