Skip to main content

tablo_macros/
lib.rs

1//! The `RecordForm`, `EmbeddedForm` and `Options` derives, re-exported by
2//! `tablo-core`.
3
4mod embedded;
5mod fields;
6mod options;
7mod record_form;
8
9use proc_macro::TokenStream;
10use syn::DeriveInput;
11
12/// Derives `EmbeddedForm` for an embedded struct or enum; documented on the `tablo-core` re-export.
13#[proc_macro_derive(EmbeddedForm, attributes(form))]
14pub fn embedded_form(input: TokenStream) -> TokenStream {
15    let input = syn::parse_macro_input!(input as DeriveInput);
16    embedded::expand(input)
17}
18
19/// Derive `RecordForm` for the typed value a resource's form writes; documented on the `tablo-core`
20/// re-export.
21#[proc_macro_derive(RecordForm, attributes(form))]
22pub fn record_form(input: TokenStream) -> TokenStream {
23    let input = syn::parse_macro_input!(input as DeriveInput);
24    record_form::expand_tokens(input).into()
25}
26
27/// Derive `Options` for a unit-variant enum; documented on the `tablo-core` re-export.
28#[proc_macro_derive(Options, attributes(option))]
29pub fn options(input: TokenStream) -> TokenStream {
30    let input = syn::parse_macro_input!(input as DeriveInput);
31    options::expand_tokens(input).into()
32}
33
34/// The path the generated code names `tablo-core` by: the `tablo` facade, which
35/// re-exports it at its root, else `::tablo_core`, either under the consumer's
36/// rename. The facade comes first: it is what an app depends on, and it
37/// reaches every path the generated code names.
38fn tablo_core_path(span: &syn::Ident, derive: &str) -> syn::Result<proc_macro2::TokenStream> {
39    let found = proc_macro_crate::crate_name("tablo")
40        .map(|found| (found, "tablo"))
41        .or_else(|_| proc_macro_crate::crate_name("tablo-core").map(|found| (found, "tablo_core")));
42    match found {
43        Ok((found, own_name)) => {
44            let name = match found {
45                proc_macro_crate::FoundCrate::Itself => own_name.to_string(),
46                proc_macro_crate::FoundCrate::Name(n) => n,
47            };
48            let ident = syn::Ident::new(&name.replace('-', "_"), proc_macro2::Span::call_site());
49            Ok(quote::quote! { ::#ident })
50        }
51        Err(_) => Err(syn::Error::new_spanned(
52            span,
53            format!("`tablo` (or `tablo-core`) must be a dependency to #[derive({derive})]"),
54        )),
55    }
56}