Skip to main content

eure_macros/
lib.rs

1use darling::FromDeriveInput;
2use syn::parse_macro_input;
3
4use crate::attrs::{ContainerAttrs, extract_container_attr_spans};
5use crate::config::MacroConfig;
6use crate::context::MacroContext;
7
8mod attrs;
9mod build_schema;
10pub(crate) mod codegen_ir_adapter;
11pub(crate) mod config;
12pub(crate) mod context;
13mod emit_ir_common;
14mod from_eure;
15mod into_eure;
16mod ir;
17mod ir_spans;
18mod must_be_text;
19mod object_key;
20
21#[proc_macro_derive(IntoEure, attributes(eure))]
22pub fn into_eure_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
23    let input = parse_macro_input!(input as syn::DeriveInput);
24    match create_context(input) {
25        Ok(context) => into_eure::derive(context).into(),
26        Err(err) => err.to_compile_error().into(),
27    }
28}
29
30#[proc_macro_derive(FromEure, attributes(eure))]
31pub fn from_eure_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
32    let input = parse_macro_input!(input as syn::DeriveInput);
33    match create_context(input) {
34        Ok(context) => from_eure::derive(context).into(),
35        Err(err) => err.to_compile_error().into(),
36    }
37}
38
39#[proc_macro_derive(ObjectKey, attributes(eure))]
40pub fn object_key_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
41    let input = parse_macro_input!(input as syn::DeriveInput);
42    match create_context(input) {
43        Ok(context) => object_key::derive(context).into(),
44        Err(err) => err.to_compile_error().into(),
45    }
46}
47
48#[proc_macro_derive(BuildSchema, attributes(eure))]
49pub fn build_schema_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
50    let input = parse_macro_input!(input as syn::DeriveInput);
51    match create_context(input) {
52        Ok(context) => build_schema::derive(context).into(),
53        Err(err) => err.to_compile_error().into(),
54    }
55}
56
57fn create_context(input: syn::DeriveInput) -> syn::Result<MacroContext> {
58    let attrs = ContainerAttrs::from_derive_input(&input).expect("Failed to parse eure attributes");
59    let attr_spans = extract_container_attr_spans(&input);
60    let mut config = MacroConfig::from_attrs(attrs, attr_spans)?;
61    if has_non_exhaustive_attr(&input.attrs) {
62        config.non_exhaustive = true;
63    }
64    Ok(MacroContext::new(config, input))
65}
66
67fn has_non_exhaustive_attr(attrs: &[syn::Attribute]) -> bool {
68    attrs
69        .iter()
70        .any(|attr| attr.path().is_ident("non_exhaustive"))
71}
72
73/// Creates a zero-sized type that only parses from a specific Text value.
74///
75/// # Syntax
76///
77/// ```ignore
78/// MustBeText!("content")           // Implicit language: `content`
79/// MustBeText!(plaintext, "content") // Plaintext language: "content"
80/// MustBeText!(rust, "content")      // Other language: rust`content`
81/// ```
82///
83/// # Example
84///
85/// ```ignore
86/// use eure_macros::MustBeText;
87///
88/// // This type only successfully parses from the text value `any`
89/// let marker = MustBeText!("any");
90/// ```
91#[proc_macro]
92#[allow(non_snake_case)]
93pub fn MustBeText(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
94    let input = parse_macro_input!(input as must_be_text::MustBeTextInput);
95    must_be_text::expand(input).into()
96}