Skip to main content

rexlang_proc_macro/
lib.rs

1#![cfg_attr(not(test), deny(clippy::unwrap_used, clippy::expect_used))]
2
3use proc_macro::TokenStream;
4
5use proc_macro2::{Span, TokenStream as TokenStream2};
6use quote::{format_ident, quote};
7use std::collections::HashMap;
8use syn::{
9    Attribute, Data, DeriveInput, Error, Fields, GenericArgument, Generics, Ident, LitStr,
10    PathArguments, Type, parse_quote, spanned::Spanned,
11};
12
13#[proc_macro_derive(Rex, attributes(rex, serde))]
14pub fn derive_rex(input: TokenStream) -> TokenStream {
15    let ast: DeriveInput = match syn::parse(input) {
16        Ok(ast) => ast,
17        Err(e) => return e.to_compile_error().into(),
18    };
19    match expand(&ast) {
20        Ok(ts) => ts.into(),
21        Err(e) => e.to_compile_error().into(),
22    }
23}
24
25struct DeriveOptions {
26    name: String,
27}
28
29fn expand(ast: &DeriveInput) -> Result<TokenStream2, Error> {
30    if ast.generics.lifetimes().next().is_some() || ast.generics.const_params().next().is_some() {
31        return Err(Error::new(
32            ast.generics.span(),
33            "`#[derive(Rex)]` only supports type parameters (no lifetimes or const generics)",
34        ));
35    }
36
37    let opts = DeriveOptions {
38        name: rex_name_from_attrs(&ast.attrs)?.unwrap_or_else(|| ast.ident.to_string()),
39    };
40
41    let rust_ident = &ast.ident;
42    let type_name = opts.name;
43    let type_param_idents: Vec<Ident> = ast
44        .generics
45        .type_params()
46        .map(|p| p.ident.clone())
47        .collect();
48    let type_param_count = type_param_idents.len();
49
50    let mut rex_type_generics = ast.generics.clone();
51    add_bound_to_type_params(
52        &mut rex_type_generics,
53        parse_quote!(::rexlang_core::RexType),
54    );
55    let (rex_type_impl_generics, rex_type_ty_generics, rex_type_where_clause) =
56        rex_type_generics.split_for_impl();
57    let rex_type_params = type_param_idents.iter().map(|ident| {
58        quote! { <#ident as ::rexlang_core::RexType>::rex_type() }
59    });
60    let rex_type_impl = quote! {
61        impl #rex_type_impl_generics ::rexlang_core::RexType for #rust_ident #rex_type_ty_generics #rex_type_where_clause {
62            fn rex_type() -> ::rexlang_core::Type {
63                let mut ty = ::rexlang_core::Type::con(#type_name, #type_param_count);
64                #( ty = ::rexlang_core::Type::app(ty, #rex_type_params); )*
65                ty
66            }
67        }
68    };
69    let adt_decl_fn = adt_decl_fn(ast, &type_name, &type_param_idents)?;
70    let mut rex_adt_generics = ast.generics.clone();
71    add_bound_to_type_params(&mut rex_adt_generics, parse_quote!(::rexlang_core::RexType));
72    let (rex_adt_impl_generics, rex_adt_ty_generics, rex_adt_where_clause) =
73        rex_adt_generics.split_for_impl();
74    let rex_adt_impl = quote! {
75        impl #rex_adt_impl_generics ::rexlang_core::RexAdt for #rust_ident #rex_adt_ty_generics #rex_adt_where_clause {
76            fn rex_adt_decl<State: Clone + Send + Sync + 'static>(
77                engine: &mut ::rexlang_core::Engine<State>,
78            ) -> Result<::rexlang_core::AdtDecl, ::rexlang_core::EngineError> {
79                #adt_decl_fn
80            }
81        }
82    };
83    let inject_fn = quote! {
84        impl #rex_adt_impl_generics #rust_ident #rex_adt_ty_generics #rex_adt_where_clause {
85            pub fn inject_rex<State: Clone + Send + Sync + 'static>(
86                engine: &mut ::rexlang_core::Engine<State>,
87            ) -> Result<(), ::rexlang_core::EngineError> {
88                <Self as ::rexlang_core::RexAdt>::inject_rex(engine)
89            }
90
91            pub fn rex_adt_decl<State: Clone + Send + Sync + 'static>(
92                engine: &mut ::rexlang_core::Engine<State>,
93            ) -> Result<::rexlang_core::AdtDecl, ::rexlang_core::EngineError> {
94                <Self as ::rexlang_core::RexAdt>::rex_adt_decl(engine)
95            }
96
97            pub fn inject_rex_with_default<State: Clone + Send + Sync + 'static>(
98                engine: &mut ::rexlang_core::Engine<State>,
99            ) -> Result<(), ::rexlang_core::EngineError>
100            where
101                Self: ::rexlang_core::RexDefault<State>,
102            {
103                <Self as ::rexlang_core::RexAdt>::inject_rex(engine)?;
104                engine.inject_rex_default_instance::<Self>()
105            }
106
107            pub fn inject_rex_with_constructor<State, Sig, H>(
108                engine: &mut ::rexlang_core::Engine<State>,
109                constructor: H,
110            ) -> Result<(), ::rexlang_core::EngineError>
111            where
112                State: Clone + Send + Sync + 'static,
113                H: ::rexlang_core::Handler<State, Sig>,
114            {
115                <Self as ::rexlang_core::RexAdt>::inject_rex(engine)?;
116                engine.export(#type_name, constructor)
117            }
118        }
119    };
120
121    let into_value_impl = into_value_impl(ast, &type_name)?;
122    let from_value_impl = from_value_impl(ast, &type_name)?;
123
124    Ok(quote! {
125        #rex_type_impl
126        #rex_adt_impl
127        #inject_fn
128        #into_value_impl
129        #from_value_impl
130    })
131}
132
133fn rex_name_from_attrs(attrs: &[Attribute]) -> Result<Option<String>, Error> {
134    for attr in attrs {
135        if !attr.path().is_ident("rex") {
136            continue;
137        }
138        let mut name: Option<String> = None;
139        attr.parse_nested_meta(|meta| {
140            if meta.path.is_ident("name") {
141                let value = meta.value()?;
142                let lit: LitStr = value.parse()?;
143                name = Some(lit.value());
144            }
145            Ok(())
146        })?;
147        return Ok(name);
148    }
149    Ok(None)
150}
151
152fn serde_rename_from_attrs(attrs: &[Attribute]) -> Result<Option<String>, Error> {
153    for attr in attrs {
154        if !attr.path().is_ident("serde") {
155            continue;
156        }
157        let mut rename: Option<String> = None;
158        attr.parse_nested_meta(|meta| {
159            if meta.path.is_ident("rename") {
160                let value = meta.value()?;
161                let lit: LitStr = value.parse()?;
162                rename = Some(lit.value());
163            } else if meta.path.is_ident("alias") {
164                // Consume and ignore aliases so serde meta parsing doesn't fail.
165                let value = meta.value()?;
166                let _lit: LitStr = value.parse()?;
167            } else if meta.path.is_ident("default") {
168                // Consume and ignore defaults (function path as string literal).
169                let value = meta.value()?;
170                let _lit: LitStr = value.parse()?;
171            }
172            Ok(())
173        })?;
174        if rename.is_some() {
175            return Ok(rename);
176        }
177    }
178    Ok(None)
179}
180
181fn adt_decl_fn(
182    ast: &DeriveInput,
183    type_name: &str,
184    type_params: &[Ident],
185) -> Result<TokenStream2, Error> {
186    let param_names: Vec<LitStr> = type_params
187        .iter()
188        .map(|p| LitStr::new(&p.to_string(), Span::call_site()))
189        .collect();
190    let param_count = param_names.len();
191    let adt_decl = if param_names.is_empty() {
192        quote! {
193            let head = ::rexlang_core::Type::con(#type_name, 0);
194            let mut adt = engine.adt_decl_from_type_with_params(&head, &[])?;
195        }
196    } else {
197        quote! {
198            let head = ::rexlang_core::Type::con(#type_name, #param_count);
199            let mut adt = engine.adt_decl_from_type_with_params(&head, &[#(#param_names,)*])?;
200        }
201    };
202
203    let mut param_bindings = Vec::new();
204    let mut param_map: HashMap<String, TokenStream2> = HashMap::new();
205    for p in type_params {
206        let p_name = p.to_string();
207        let p_lit = LitStr::new(&p_name, Span::call_site());
208        let p_ident = format_ident!("__rex_param_{p_name}", span = Span::call_site());
209        param_bindings.push(quote! {
210            let #p_ident = adt
211                .param_type(&::rexlang_core::intern(#p_lit))
212                .ok_or_else(|| ::rexlang_core::EngineError::UnknownType(::rexlang_core::intern(#type_name)))?;
213        });
214        param_map.insert(p_name, quote!(#p_ident.clone()));
215    }
216
217    match &ast.data {
218        Data::Struct(data) => match &data.fields {
219            Fields::Named(fields) => {
220                let ctor = type_name;
221                let mut field_inits = Vec::new();
222                for field in &fields.named {
223                    let field_ident = field
224                        .ident
225                        .as_ref()
226                        .ok_or_else(|| Error::new(field.span(), "expected named field"))?;
227                    let mut field_name = field_ident.to_string();
228                    if let Some(rename) = serde_rename_from_attrs(&field.attrs)? {
229                        field_name = rename;
230                    }
231                    let field_ty = rex_type_expr(&field.ty, &param_map)?;
232                    field_inits.push(quote! {
233                        ( ::rexlang_core::intern(#field_name), #field_ty )
234                    });
235                }
236                Ok(quote! {{
237                    #adt_decl
238                    #(#param_bindings)*
239                    let record = ::rexlang_core::Type::record(::std::vec![#(#field_inits,)*]);
240                    adt.add_variant(::rexlang_core::intern(#ctor), ::std::vec![record]);
241                    Ok(adt)
242                }})
243            }
244            Fields::Unnamed(fields) => {
245                let ctor = type_name;
246                let mut args = Vec::new();
247                for field in &fields.unnamed {
248                    let ty = rex_type_expr(&field.ty, &param_map)?;
249                    args.push(ty);
250                }
251                Ok(quote! {{
252                    #adt_decl
253                    #(#param_bindings)*
254                    adt.add_variant(::rexlang_core::intern(#ctor), ::std::vec![#(#args,)*]);
255                    Ok(adt)
256                }})
257            }
258            Fields::Unit => Ok(quote! {{
259                #adt_decl
260                #(#param_bindings)*
261                adt.add_variant(::rexlang_core::intern(#type_name), ::std::vec![]);
262                Ok(adt)
263            }}),
264        },
265        Data::Enum(data) => {
266            let mut variants = Vec::new();
267            for variant in &data.variants {
268                let mut variant_name = variant.ident.to_string();
269                if let Some(rename) = serde_rename_from_attrs(&variant.attrs)? {
270                    variant_name = rename;
271                }
272                let args = match &variant.fields {
273                    Fields::Unit => Vec::new(),
274                    Fields::Unnamed(fields) => {
275                        let mut out = Vec::new();
276                        for field in &fields.unnamed {
277                            out.push(rex_type_expr(&field.ty, &param_map)?);
278                        }
279                        out
280                    }
281                    Fields::Named(fields) => {
282                        let mut field_inits = Vec::new();
283                        for field in &fields.named {
284                            let field_ident = field
285                                .ident
286                                .as_ref()
287                                .ok_or_else(|| Error::new(field.span(), "expected named field"))?;
288                            let mut field_name = field_ident.to_string();
289                            if let Some(rename) = serde_rename_from_attrs(&field.attrs)? {
290                                field_name = rename;
291                            }
292                            let field_ty = rex_type_expr(&field.ty, &param_map)?;
293                            field_inits.push(quote! {
294                                ( ::rexlang_core::intern(#field_name), #field_ty )
295                            });
296                        }
297                        let record = quote! {
298                            ::rexlang_core::Type::record(::std::vec![#(#field_inits,)*])
299                        };
300                        vec![record]
301                    }
302                };
303                variants.push(quote! {
304                    adt.add_variant(::rexlang_core::intern(#variant_name), ::std::vec![#(#args,)*]);
305                });
306            }
307            Ok(quote! {{
308                #adt_decl
309                #(#param_bindings)*
310                #(#variants)*
311                Ok(adt)
312            }})
313        }
314        Data::Union(_) => Err(Error::new(
315            ast.span(),
316            "`#[derive(Rex)]` only supports structs and enums",
317        )),
318    }
319}
320
321fn rex_type_expr(
322    ty: &Type,
323    adt_params: &HashMap<String, TokenStream2>,
324) -> Result<TokenStream2, Error> {
325    match ty {
326        Type::Tuple(tuple) => {
327            let elems = tuple
328                .elems
329                .iter()
330                .map(|t| rex_type_expr(t, adt_params))
331                .collect::<Result<Vec<_>, _>>()?;
332            Ok(quote! { ::rexlang_core::Type::tuple(::std::vec![#(#elems,)*]) })
333        }
334        Type::Path(type_path) => {
335            if type_path.qself.is_none() && type_path.path.segments.len() == 1 {
336                let seg = type_path
337                    .path
338                    .segments
339                    .last()
340                    .ok_or_else(|| Error::new(type_path.span(), "unsupported type path"))?;
341                let ident = seg.ident.to_string();
342                if let Some(param_ty) = adt_params.get(&ident) {
343                    return Ok(param_ty.clone());
344                }
345            }
346
347            let seg = type_path
348                .path
349                .segments
350                .last()
351                .ok_or_else(|| Error::new(type_path.span(), "unsupported type path"))?;
352            let ident = seg.ident.to_string();
353            let args = match &seg.arguments {
354                PathArguments::AngleBracketed(args) => args
355                    .args
356                    .iter()
357                    .filter_map(|a| match a {
358                        GenericArgument::Type(t) => Some(t),
359                        _ => None,
360                    })
361                    .collect::<Vec<_>>(),
362                _ => Vec::new(),
363            };
364
365            match ident.as_str() {
366                "Vec" => {
367                    let [inner] = args.as_slice() else {
368                        return Err(Error::new(seg.span(), "expected `Vec<T>`"));
369                    };
370                    let inner = rex_type_expr(inner, adt_params)?;
371                    Ok(quote! {
372                        ::rexlang_core::Type::app(
373                            ::rexlang_core::Type::builtin(::rexlang_core::BuiltinTypeId::List),
374                            #inner
375                        )
376                    })
377                }
378                "HashMap" | "BTreeMap" => {
379                    let [k, v] = args.as_slice() else {
380                        return Err(Error::new(seg.span(), "expected `HashMap<K, V>`"));
381                    };
382                    if !is_string_type(k) {
383                        return Err(Error::new(
384                            k.span(),
385                            "only `HashMap<String, V>` is supported for Rex dictionaries",
386                        ));
387                    }
388                    let v = rex_type_expr(v, adt_params)?;
389                    Ok(quote! {
390                        ::rexlang_core::Type::app(
391                            ::rexlang_core::Type::builtin(::rexlang_core::BuiltinTypeId::Dict),
392                            #v
393                        )
394                    })
395                }
396                "Option" => {
397                    let [inner] = args.as_slice() else {
398                        return Err(Error::new(seg.span(), "expected `Option<T>`"));
399                    };
400                    let inner = rex_type_expr(inner, adt_params)?;
401                    Ok(quote! {
402                        ::rexlang_core::Type::app(
403                            ::rexlang_core::Type::builtin(::rexlang_core::BuiltinTypeId::Option),
404                            #inner
405                        )
406                    })
407                }
408                "Result" => {
409                    let [ok, err] = args.as_slice() else {
410                        return Err(Error::new(seg.span(), "expected `Result<T, E>`"));
411                    };
412                    let ok = rex_type_expr(ok, adt_params)?;
413                    let err = rex_type_expr(err, adt_params)?;
414                    Ok(quote! {
415                        ::rexlang_core::Type::app(
416                            ::rexlang_core::Type::app(
417                                ::rexlang_core::Type::builtin(::rexlang_core::BuiltinTypeId::Result),
418                                #err
419                            ),
420                            #ok
421                        )
422                    })
423                }
424                _ => Ok(quote! { <#type_path as ::rexlang_core::RexType>::rex_type() }),
425            }
426        }
427        other => Err(Error::new(
428            other.span(),
429            "unsupported field type for Rex mapping",
430        )),
431    }
432}
433
434fn into_value_expr(expr: TokenStream2, ty: &Type) -> Result<TokenStream2, Error> {
435    match ty {
436        Type::Tuple(tuple) => {
437            let vars: Vec<Ident> = (0..tuple.elems.len())
438                .map(|i| format_ident!("__rex_t{i}", span = Span::call_site()))
439                .collect();
440            let encs = vars
441                .iter()
442                .zip(tuple.elems.iter())
443                .map(|(v, t)| into_value_expr(quote!(#v), t))
444                .collect::<Result<Vec<_>, _>>()?;
445            Ok(quote! {{
446                let (#(#vars,)*) = #expr;
447                heap.alloc_tuple(::std::vec![#(#encs,)*])?
448            }})
449        }
450        Type::Path(type_path) => {
451            let seg = type_path
452                .path
453                .segments
454                .last()
455                .ok_or_else(|| Error::new(type_path.span(), "unsupported type path"))?;
456            let ident = seg.ident.to_string();
457            let args = match &seg.arguments {
458                PathArguments::AngleBracketed(args) => args
459                    .args
460                    .iter()
461                    .filter_map(|a| match a {
462                        GenericArgument::Type(t) => Some(t),
463                        _ => None,
464                    })
465                    .collect::<Vec<_>>(),
466                _ => Vec::new(),
467            };
468
469            match ident.as_str() {
470                "Vec" => {
471                    let [inner] = args.as_slice() else {
472                        return Err(Error::new(seg.span(), "expected `Vec<T>`"));
473                    };
474                    let inner_encode = into_value_expr(quote!(item), inner)?;
475                    Ok(quote! {{
476                        let mut out =
477                            heap.alloc_adt(::rexlang_core::intern("Empty"), ::std::vec::Vec::new())?;
478                        for item in #expr.into_iter().rev() {
479                            out = heap
480                                .alloc_adt(
481                                    ::rexlang_core::intern("Cons"),
482                                    ::std::vec![#inner_encode, out],
483                                )?;
484                        }
485                        out
486                    }})
487                }
488                "HashMap" | "BTreeMap" => {
489                    let [k, v] = args.as_slice() else {
490                        return Err(Error::new(seg.span(), "expected `HashMap<K, V>`"));
491                    };
492                    if !is_string_type(k) {
493                        return Err(Error::new(
494                            k.span(),
495                            "only `HashMap<String, V>` is supported for Rex dictionaries",
496                        ));
497                    }
498                    let v_encode = into_value_expr(quote!(v), v)?;
499                    Ok(quote! {{
500                        let mut out = ::std::collections::BTreeMap::new();
501                        for (k, v) in #expr {
502                            out.insert(::rexlang_core::intern(&k), #v_encode);
503                        }
504                        heap.alloc_dict(out)?
505                    }})
506                }
507                "Option" => {
508                    let [inner] = args.as_slice() else {
509                        return Err(Error::new(seg.span(), "expected `Option<T>`"));
510                    };
511                    let inner_encode = into_value_expr(quote!(v), inner)?;
512                    Ok(quote! {{
513                        match #expr {
514                            Some(v) => heap
515                                .alloc_adt(::rexlang_core::intern("Some"), ::std::vec![#inner_encode])?,
516                            None => heap
517                                .alloc_adt(::rexlang_core::intern("None"), ::std::vec::Vec::new())?,
518                        }
519                    }})
520                }
521                "Result" => {
522                    let [ok_ty, err_ty] = args.as_slice() else {
523                        return Err(Error::new(seg.span(), "expected `Result<T, E>`"));
524                    };
525                    let ok_encode = into_value_expr(quote!(v), ok_ty)?;
526                    let err_encode = into_value_expr(quote!(e), err_ty)?;
527                    Ok(quote! {{
528                        match #expr {
529                            Ok(v) => heap
530                                .alloc_adt(::rexlang_core::intern("Ok"), ::std::vec![#ok_encode])?,
531                            Err(e) => heap
532                                .alloc_adt(::rexlang_core::intern("Err"), ::std::vec![#err_encode])?,
533                        }
534                    }})
535                }
536                _ => Ok(quote! { ::rexlang_core::IntoPointer::into_pointer(#expr, heap)? }),
537            }
538        }
539        other => Err(Error::new(
540            other.span(),
541            "unsupported field type for Rex encoding",
542        )),
543    }
544}
545
546fn from_value_expr(
547    value_expr: TokenStream2,
548    ty: &Type,
549    name_expr: TokenStream2,
550) -> Result<TokenStream2, Error> {
551    match ty {
552        Type::Tuple(tuple) => {
553            let elem_tys = tuple.elems.iter().collect::<Vec<_>>();
554            let indices: Vec<usize> = (0..elem_tys.len()).collect();
555            let decs = elem_tys
556                .iter()
557                .zip(indices.iter())
558                .map(|(t, i)| {
559                    from_value_expr(
560                        quote!(&heap.get(&items[#i])?.as_ref().clone()),
561                        t,
562                        name_expr.clone(),
563                    )
564                })
565                .collect::<Result<Vec<_>, _>>()?;
566            let len = elem_tys.len();
567            Ok(quote! {{
568                match #value_expr {
569                    ::rexlang_core::Value::Tuple(items) if items.len() == #len => {
570                        Ok((#(#decs?,)*))
571                    }
572                    other => Err(::rexlang_core::EngineError::NativeType { expected: "tuple".into(),
573                        got: ::rexlang_core::value_debug(heap, &other)
574                            .unwrap_or_else(|err| format!("<display error: {err}>")),
575                    }),
576                }
577            }})
578        }
579        Type::Path(type_path) => {
580            let seg = type_path
581                .path
582                .segments
583                .last()
584                .ok_or_else(|| Error::new(type_path.span(), "unsupported type path"))?;
585            let ident = seg.ident.to_string();
586            let args = match &seg.arguments {
587                PathArguments::AngleBracketed(args) => args
588                    .args
589                    .iter()
590                    .filter_map(|a| match a {
591                        GenericArgument::Type(t) => Some(t),
592                        _ => None,
593                    })
594                    .collect::<Vec<_>>(),
595                _ => Vec::new(),
596            };
597
598            match ident.as_str() {
599                "Vec" => {
600                    let [inner] = args.as_slice() else {
601                        return Err(Error::new(seg.span(), "expected `Vec<T>`"));
602                    };
603                    let inner_decode = from_value_expr(
604                        quote!(&heap.get(&args[0])?.as_ref().clone()),
605                        inner,
606                        name_expr.clone(),
607                    )?;
608                    Ok(quote! {{
609                        let mut out = ::std::vec::Vec::new();
610                        let mut cur = (#value_expr).clone();
611                        loop {
612                            match &cur {
613                                ::rexlang_core::Value::Adt(tag, args) if tag.as_ref() == "Empty" && args.is_empty() => {
614                                    break Ok(out);
615                                }
616                                ::rexlang_core::Value::Adt(tag, args) if tag.as_ref() == "Cons" && args.len() == 2 => {
617                                    let v = #inner_decode?;
618                                    out.push(v);
619                                    cur = heap.get(&args[1])?.as_ref().clone();
620                                }
621                                other => {
622                                    break Err(::rexlang_core::EngineError::NativeType { expected: "list".into(),
623                                        got: ::rexlang_core::value_debug(heap, &other)
624                                            .unwrap_or_else(|err| format!("<display error: {err}>")),
625                                    });
626                                }
627                            }
628                        }
629                    }})
630                }
631                "HashMap" | "BTreeMap" => {
632                    let [k, v] = args.as_slice() else {
633                        return Err(Error::new(seg.span(), "expected `HashMap<K, V>`"));
634                    };
635                    if !is_string_type(k) {
636                        return Err(Error::new(
637                            k.span(),
638                            "only `HashMap<String, V>` is supported for Rex dictionaries",
639                        ));
640                    }
641                    let v_decode = from_value_expr(
642                        quote!(&heap.get(&v)?.as_ref().clone()),
643                        v,
644                        name_expr.clone(),
645                    )?;
646                    Ok(quote! {{
647                        match #value_expr {
648                            ::rexlang_core::Value::Dict(map) => {
649                                let mut out = ::std::collections::HashMap::new();
650                                for (k, v) in map {
651                                    let decoded = #v_decode?;
652                                    out.insert(k.as_ref().to_string(), decoded);
653                                }
654                                Ok(out)
655                            }
656                            other => Err(::rexlang_core::EngineError::NativeType { expected: "dict".into(),
657                                got: ::rexlang_core::value_debug(heap, &other)
658                                    .unwrap_or_else(|err| format!("<display error: {err}>")),
659                            }),
660                        }
661                    }})
662                }
663                "Option" => {
664                    let [inner] = args.as_slice() else {
665                        return Err(Error::new(seg.span(), "expected `Option<T>`"));
666                    };
667                    let inner_decode = from_value_expr(
668                        quote!(&heap.get(&args[0])?.as_ref().clone()),
669                        inner,
670                        name_expr.clone(),
671                    )?;
672                    Ok(quote! {{
673                        match #value_expr {
674                            ::rexlang_core::Value::Adt(tag, args) if tag.as_ref() == "None" && args.is_empty() => Ok(None),
675                            ::rexlang_core::Value::Adt(tag, args) if tag.as_ref() == "Some" && args.len() == 1 => Ok(Some(#inner_decode?)),
676                            other => Err(::rexlang_core::EngineError::NativeType { expected: "option".into(),
677                                got: ::rexlang_core::value_debug(heap, &other)
678                                    .unwrap_or_else(|err| format!("<display error: {err}>")),
679                            }),
680                        }
681                    }})
682                }
683                "Result" => {
684                    let [ok_ty, err_ty] = args.as_slice() else {
685                        return Err(Error::new(seg.span(), "expected `Result<T, E>`"));
686                    };
687                    let ok_decode = from_value_expr(
688                        quote!(&heap.get(&args[0])?.as_ref().clone()),
689                        ok_ty,
690                        name_expr.clone(),
691                    )?;
692                    let err_decode = from_value_expr(
693                        quote!(&heap.get(&args[0])?.as_ref().clone()),
694                        err_ty,
695                        name_expr.clone(),
696                    )?;
697                    Ok(quote! {{
698                        match #value_expr {
699                            ::rexlang_core::Value::Adt(tag, args) if tag.as_ref() == "Ok" && args.len() == 1 => Ok(Ok(#ok_decode?)),
700                            ::rexlang_core::Value::Adt(tag, args) if tag.as_ref() == "Err" && args.len() == 1 => Ok(Err(#err_decode?)),
701                            other => Err(::rexlang_core::EngineError::NativeType { expected: "result".into(),
702                                got: ::rexlang_core::value_debug(heap, &other)
703                                    .unwrap_or_else(|err| format!("<display error: {err}>")),
704                            }),
705                        }
706                    }})
707                }
708                _ => Ok(quote! {{
709                    let __rex_value: ::rexlang_core::Value = (#value_expr).clone();
710                    let __rex_ptr = heap.alloc_value(__rex_value)?;
711                    <#type_path as ::rexlang_core::FromPointer>::from_pointer(heap, &__rex_ptr)
712                }}),
713            }
714        }
715        other => Err(Error::new(
716            other.span(),
717            "unsupported field type for Rex decoding",
718        )),
719    }
720}
721
722fn is_string_type(ty: &Type) -> bool {
723    match ty {
724        Type::Path(p) => p
725            .path
726            .segments
727            .last()
728            .map(|s| s.ident == "String")
729            .unwrap_or(false),
730        _ => false,
731    }
732}
733
734fn add_bound_to_type_params(generics: &mut Generics, bound: syn::TypeParamBound) {
735    for param in generics.type_params_mut() {
736        param.bounds.push(bound.clone());
737    }
738}
739
740fn into_value_impl(ast: &DeriveInput, type_name: &str) -> Result<TokenStream2, Error> {
741    let rust_ident = &ast.ident;
742    let ctor = type_name;
743
744    let body = match &ast.data {
745        Data::Struct(data) => match &data.fields {
746            Fields::Named(fields) => {
747                let mut inserts = Vec::new();
748                for field in &fields.named {
749                    let ident = field
750                        .ident
751                        .as_ref()
752                        .ok_or_else(|| Error::new(field.span(), "expected named field"))?;
753                    let mut name = ident.to_string();
754                    if let Some(rename) = serde_rename_from_attrs(&field.attrs)? {
755                        name = rename;
756                    }
757                    let enc = into_value_expr(quote!(self.#ident), &field.ty)?;
758                    inserts.push(quote! {
759                        map.insert(::rexlang_core::intern(#name), #enc);
760                    });
761                }
762                quote! {{
763                    let mut map = ::std::collections::BTreeMap::new();
764                    #(#inserts)*
765                    let dict = heap.alloc_dict(map)?;
766                    heap.alloc_adt(::rexlang_core::intern(#ctor), ::std::vec![dict])?
767                }}
768            }
769            Fields::Unnamed(fields) => {
770                let mut args = Vec::new();
771                let mut bindings = Vec::new();
772                for (idx, field) in fields.unnamed.iter().enumerate() {
773                    let v = format_ident!("__rex_f{idx}", span = Span::call_site());
774                    bindings.push(v.clone());
775                    args.push(into_value_expr(quote!(#v), &field.ty)?);
776                }
777                quote! {{
778                    let Self(#(#bindings,)*) = self;
779                    heap.alloc_adt(::rexlang_core::intern(#ctor), ::std::vec![#(#args,)*])?
780                }}
781            }
782            Fields::Unit => quote! {
783                heap.alloc_adt(::rexlang_core::intern(#ctor), ::std::vec::Vec::new())?
784            },
785        },
786        Data::Enum(data) => {
787            let mut arms = Vec::new();
788            for variant in &data.variants {
789                let variant_ident = &variant.ident;
790                let mut variant_name = variant_ident.to_string();
791                if let Some(rename) = serde_rename_from_attrs(&variant.attrs)? {
792                    variant_name = rename;
793                }
794                let arm = match &variant.fields {
795                    Fields::Unit => quote! {
796                        Self::#variant_ident => heap
797                            .alloc_adt(::rexlang_core::intern(#variant_name), ::std::vec::Vec::new())?
798                    },
799                    Fields::Unnamed(fields) => {
800                        let vars: Vec<Ident> = (0..fields.unnamed.len())
801                            .map(|i| format_ident!("__rex_v{i}", span = Span::call_site()))
802                            .collect();
803                        let encs = vars
804                            .iter()
805                            .zip(fields.unnamed.iter())
806                            .map(|(v, f)| into_value_expr(quote!(#v), &f.ty))
807                            .collect::<Result<Vec<_>, _>>()?;
808                        quote! {
809                            Self::#variant_ident(#(#vars,)*) => heap
810                                .alloc_adt(::rexlang_core::intern(#variant_name), ::std::vec![#(#encs,)*])?
811                        }
812                    }
813                    Fields::Named(fields) => {
814                        let mut vars = Vec::new();
815                        let mut inserts = Vec::new();
816                        for field in &fields.named {
817                            let ident = field
818                                .ident
819                                .as_ref()
820                                .ok_or_else(|| Error::new(field.span(), "expected named field"))?;
821                            vars.push(ident.clone());
822                            let mut name = ident.to_string();
823                            if let Some(rename) = serde_rename_from_attrs(&field.attrs)? {
824                                name = rename;
825                            }
826                            let enc = into_value_expr(quote!(#ident), &field.ty)?;
827                            inserts.push(quote! {
828                                map.insert(::rexlang_core::intern(#name), #enc);
829                            });
830                        }
831                        quote! {
832                            Self::#variant_ident { #(#vars,)* } => {
833                                let mut map = ::std::collections::BTreeMap::new();
834                                #(#inserts)*
835                                let dict = heap.alloc_dict(map)?;
836                                heap.alloc_adt(::rexlang_core::intern(#variant_name), ::std::vec![dict])?
837                            }
838                        }
839                    }
840                };
841                arms.push(arm);
842            }
843            quote! {{
844                match self {
845                    #(#arms,)*
846                }
847            }}
848        }
849        Data::Union(_) => {
850            return Err(Error::new(
851                ast.span(),
852                "`#[derive(Rex)]` only supports structs and enums",
853            ));
854        }
855    };
856
857    let mut generics = ast.generics.clone();
858    add_bound_to_type_params(&mut generics, parse_quote!(::rexlang_core::IntoPointer));
859    let (impl_generics, _, where_clause) = generics.split_for_impl();
860    let (_, ty_generics, _) = generics.split_for_impl();
861
862    Ok(quote! {
863        impl #impl_generics ::rexlang_core::IntoPointer for #rust_ident #ty_generics #where_clause {
864            fn into_pointer(
865                self,
866                heap: &::rexlang_core::Heap,
867            ) -> ::std::result::Result<::rexlang_core::Pointer, ::rexlang_core::EngineError> {
868                Ok(#body)
869            }
870        }
871    })
872}
873
874fn from_value_impl(ast: &DeriveInput, type_name: &str) -> Result<TokenStream2, Error> {
875    let rust_ident = &ast.ident;
876    let name_expr = quote!(name);
877
878    let body = match &ast.data {
879        Data::Struct(data) => match &data.fields {
880            Fields::Named(fields) => {
881                let mut field_decodes = Vec::new();
882                let mut field_idents = Vec::new();
883                for field in &fields.named {
884                    let ident = field
885                        .ident
886                        .as_ref()
887                        .ok_or_else(|| Error::new(field.span(), "expected named field"))?;
888                    field_idents.push(ident.clone());
889                    let mut name = ident.to_string();
890                    if let Some(rename) = serde_rename_from_attrs(&field.attrs)? {
891                        name = rename;
892                    }
893                    let key = quote!(::rexlang_core::intern(#name));
894                    let decode = from_value_expr(
895                        quote!(&heap.get(&v)?.as_ref().clone()),
896                        &field.ty,
897                        name_expr.clone(),
898                    )?;
899                    field_decodes.push(quote! {
900                        let v = map.get(&#key).ok_or_else(|| ::rexlang_core::EngineError::NativeType { expected: format!("missing field `{}`", #name),
901                            got: "dict".into(),
902                        })?;
903                        let #ident = #decode?;
904                    });
905                }
906                Ok(quote! {{
907                    match value {
908                        ::rexlang_core::Value::Adt(tag, args)
909                            if (tag.as_ref() == #type_name
910                                || tag.as_ref().rsplit('.').next() == Some(#type_name))
911                                && args.len() == 1 =>
912                        {
913                            match heap.get(&args[0])?.as_ref().clone() {
914                                ::rexlang_core::Value::Dict(map) => {
915                                    #(#field_decodes)*
916                                    Ok(Self { #(#field_idents,)* })
917                                }
918                                other => Err(::rexlang_core::EngineError::NativeType { expected: "dict".into(),
919                                    got: ::rexlang_core::value_debug(heap, &other)
920                                        .unwrap_or_else(|err| format!("<display error: {err}>")),
921                                }),
922                            }
923                        }
924                        other => Err(::rexlang_core::EngineError::NativeType { expected: #type_name.into(),
925                            got: ::rexlang_core::value_debug(heap, &other)
926                                .unwrap_or_else(|err| format!("<display error: {err}>")),
927                        }),
928                    }
929                }})
930            }
931            Fields::Unnamed(fields) => {
932                let mut decs = Vec::new();
933                for (idx, field) in fields.unnamed.iter().enumerate() {
934                    let decode = from_value_expr(
935                        quote!(&heap.get(&args[#idx])?.as_ref().clone()),
936                        &field.ty,
937                        name_expr.clone(),
938                    )?;
939                    decs.push(quote!(#decode?));
940                }
941                let len = fields.unnamed.len();
942                Ok(quote! {{
943                    match value {
944                        ::rexlang_core::Value::Adt(tag, args)
945                            if (tag.as_ref() == #type_name
946                                || tag.as_ref().rsplit('.').next() == Some(#type_name))
947                                && args.len() == #len =>
948                        {
949                            Ok(Self(#(#decs,)*))
950                        }
951                        other => Err(::rexlang_core::EngineError::NativeType { expected: #type_name.into(),
952                            got: ::rexlang_core::value_debug(heap, &other)
953                                .unwrap_or_else(|err| format!("<display error: {err}>")),
954                        }),
955                    }
956                }})
957            }
958            Fields::Unit => Ok(quote! {{
959                match value {
960                    ::rexlang_core::Value::Adt(tag, args)
961                        if (tag.as_ref() == #type_name
962                            || tag.as_ref().rsplit('.').next() == Some(#type_name))
963                            && args.is_empty() =>
964                    {
965                        Ok(Self)
966                    }
967                    other => Err(::rexlang_core::EngineError::NativeType { expected: #type_name.into(),
968                        got: ::rexlang_core::value_debug(heap, &other)
969                            .unwrap_or_else(|err| format!("<display error: {err}>")),
970                    }),
971                }
972            }}),
973        },
974        Data::Enum(data) => {
975            let mut arms = Vec::new();
976            for variant in &data.variants {
977                let variant_ident = &variant.ident;
978                let mut variant_name = variant_ident.to_string();
979                if let Some(rename) = serde_rename_from_attrs(&variant.attrs)? {
980                    variant_name = rename;
981                }
982                let arm = match &variant.fields {
983                    Fields::Unit => quote! {
984                        ::rexlang_core::Value::Adt(tag, args)
985                            if (tag.as_ref() == #variant_name
986                                || tag.as_ref().rsplit('.').next() == Some(#variant_name))
987                                && args.is_empty() =>
988                        {
989                            Ok(Self::#variant_ident)
990                        }
991                    },
992                    Fields::Unnamed(fields) => {
993                        let len = fields.unnamed.len();
994                        let vals = fields
995                            .unnamed
996                            .iter()
997                            .enumerate()
998                            .map(|(i, f)| {
999                                from_value_expr(
1000                                    quote!(&heap.get(&args[#i])?.as_ref().clone()),
1001                                    &f.ty,
1002                                    name_expr.clone(),
1003                                )
1004                            })
1005                            .collect::<Result<Vec<_>, _>>()?
1006                            .into_iter()
1007                            .map(|d| quote!(#d?))
1008                            .collect::<Vec<_>>();
1009                        quote! {
1010                            ::rexlang_core::Value::Adt(tag, args)
1011                                if (tag.as_ref() == #variant_name
1012                                    || tag.as_ref().rsplit('.').next() == Some(#variant_name))
1013                                    && args.len() == #len =>
1014                            {
1015                                Ok(Self::#variant_ident(#(#vals,)*))
1016                            }
1017                        }
1018                    }
1019                    Fields::Named(fields) => {
1020                        let mut field_decodes = Vec::new();
1021                        let mut fields_init = Vec::new();
1022                        for field in &fields.named {
1023                            let ident = field
1024                                .ident
1025                                .as_ref()
1026                                .ok_or_else(|| Error::new(field.span(), "expected named field"))?;
1027                            fields_init.push(ident.clone());
1028                            let mut name = ident.to_string();
1029                            if let Some(rename) = serde_rename_from_attrs(&field.attrs)? {
1030                                name = rename;
1031                            }
1032                            let key = quote!(::rexlang_core::intern(#name));
1033                            let decode = from_value_expr(
1034                                quote!(&heap.get(&v)?.as_ref().clone()),
1035                                &field.ty,
1036                                name_expr.clone(),
1037                            )?;
1038                            field_decodes.push(quote! {
1039                                let v = map.get(&#key).ok_or_else(|| ::rexlang_core::EngineError::NativeType { expected: format!("missing field `{}`", #name),
1040                                    got: "dict".into(),
1041                                })?;
1042                                let #ident = #decode?;
1043                            });
1044                        }
1045                        quote! {
1046                            ::rexlang_core::Value::Adt(tag, args)
1047                                if (tag.as_ref() == #variant_name
1048                                    || tag.as_ref().rsplit('.').next() == Some(#variant_name))
1049                                    && args.len() == 1 =>
1050                            {
1051                                match heap.get(&args[0])?.as_ref().clone() {
1052                                    ::rexlang_core::Value::Dict(map) => {
1053                                        #(#field_decodes)*
1054                                        Ok(Self::#variant_ident { #(#fields_init,)* })
1055                                    }
1056                                    other => Err(::rexlang_core::EngineError::NativeType { expected: "dict".into(),
1057                                        got: ::rexlang_core::value_debug(heap, &other)
1058                                            .unwrap_or_else(|err| format!("<display error: {err}>")),
1059                                    }),
1060                                }
1061                            }
1062                        }
1063                    }
1064                };
1065                arms.push(arm);
1066            }
1067
1068            Ok(quote! {{
1069                match value {
1070                    #(#arms,)*
1071                    other => Err(::rexlang_core::EngineError::NativeType { expected: #type_name.into(),
1072                        got: ::rexlang_core::value_debug(heap, &other)
1073                            .unwrap_or_else(|err| format!("<display error: {err}>")),
1074                    }),
1075                }
1076            }})
1077        }
1078        Data::Union(_) => Err(Error::new(
1079            ast.span(),
1080            "`#[derive(Rex)]` only supports structs and enums",
1081        )),
1082    }?;
1083
1084    let mut generics = ast.generics.clone();
1085    add_bound_to_type_params(&mut generics, parse_quote!(::rexlang_core::FromPointer));
1086    let (impl_generics, _, where_clause) = generics.split_for_impl();
1087    let (_, ty_generics, _) = generics.split_for_impl();
1088
1089    Ok(quote! {
1090        impl #impl_generics ::rexlang_core::FromPointer for #rust_ident #ty_generics #where_clause {
1091            fn from_pointer(
1092                heap: &::rexlang_core::Heap,
1093                pointer: &::rexlang_core::Pointer,
1094            ) -> Result<Self, ::rexlang_core::EngineError> {
1095                let value = heap.get(&pointer)?.as_ref().clone();
1096                #body
1097            }
1098        }
1099    })
1100}