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 let value = meta.value()?;
172 let _lit: LitStr = value.parse()?;
173 } else if meta.path.is_ident("default") {
174 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, ¶m_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, ¶m_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, ¶m_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, ¶m_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}