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