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