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