Skip to main content

nearest_derive/
lib.rs

1//! Derive macros for the `nearest` crate.
2
3mod attrs;
4mod emit;
5mod emit_proxy;
6mod flat;
7mod util;
8
9use proc_macro::TokenStream;
10use quote::quote;
11use syn::{Data, parse_macro_input};
12
13/// Derive `Flat` and `Emit` for region-based storage.
14///
15/// Generates implementations for both the `Flat` marker trait and the `Emit`
16/// builder trait, enabling declarative region construction.
17///
18/// # Field attributes
19///
20/// ## `#[flat(into)]`
21///
22/// On a primitive or `Other`-classified field, the generated `make()` builder
23/// accepts `impl Into<T>` instead of `T`. This allows callers to pass values
24/// that can be cheaply converted.
25///
26/// ```ignore
27/// #[derive(Flat)]
28/// struct Inst {
29///   #[flat(into)]
30///   op: u16,
31///   typ: Type,
32/// }
33///
34/// // Now `op` accepts any `impl Into<u16>`:
35/// Inst::make(42u8, Type(0))
36/// ```
37///
38/// # Variant attributes
39///
40/// ## `#[flat(rename = "name")]`
41///
42/// On an enum variant, overrides the generated `make_*` method name.
43///
44/// ```ignore
45/// #[derive(Flat)]
46/// #[repr(C, u8)]
47/// enum Term {
48///   #[flat(rename = "ret")]
49///   Return { values: NearList<Value> },
50///   Jmp(Jmp),
51/// }
52///
53/// // Instead of `Term::make_return(...)`:
54/// Term::ret(...)
55/// ```
56#[proc_macro_derive(Flat, attributes(flat))]
57pub fn derive_flat(input: TokenStream) -> TokenStream {
58  let input = parse_macro_input!(input as syn::DeriveInput);
59  if let Data::Union(ref u) = input.data {
60    return TokenStream::from(
61      syn::Error::new_spanned(u.union_token, "Flat cannot be derived for unions")
62        .to_compile_error(),
63    );
64  }
65  if let Err(err) = attrs::validate_all_attrs(&input) {
66    return TokenStream::from(err.to_compile_error());
67  }
68  if let Data::Enum(ref data) = input.data
69    && let Some(err) = flat::validate_enum(&input, data)
70  {
71    return TokenStream::from(err);
72  }
73  let flat_impl = flat::gen_flat_impl(&input);
74  let emit_impl = emit::gen_emit_impl(&input);
75  TokenStream::from(quote! { #flat_impl #emit_impl })
76}
77
78/// Derive [`Emit<T>`] for a proxy enum that dispatches to inner builders.
79///
80/// Each variant must be a single-field newtype. The target type is specified
81/// via `#[emit(TargetType)]`. All generic type parameters receive an
82/// `Emit<TargetType>` bound.
83///
84/// # Example
85///
86/// ```ignore
87/// #[derive(Emit)]
88/// #[emit(Block)]
89/// enum BlockEmit<A, B, C> {
90///   Br(A),
91///   Brif(B),
92///   Call(C),
93/// }
94/// ```
95///
96/// This generates `unsafe impl<A: Emit<Block>, B: Emit<Block>, C: Emit<Block>> Emit<Block> for BlockEmit<A, B, C>`,
97/// where each variant delegates `write_at` to its inner value.
98#[proc_macro_derive(Emit, attributes(emit))]
99pub fn derive_emit(input: TokenStream) -> TokenStream {
100  let input = parse_macro_input!(input as syn::DeriveInput);
101  TokenStream::from(emit_proxy::gen_emit_proxy(&input))
102}