Skip to main content

better_duck_macros/
lib.rs

1//! Procedural macros for `better-duck` user-defined functions.
2//!
3//! This crate is not meant to be used directly — depend on `better-duck-core`
4//! with the `udf` feature enabled, which re-exports [`duckdb_scalar`] and
5//! [`duckdb_table_function`].
6
7mod attrs;
8mod scalar;
9mod sig;
10mod table;
11
12use proc_macro::TokenStream;
13use syn::{parse_macro_input, ItemFn};
14
15/// Registers a plain Rust function as a DuckDB scalar function.
16///
17/// See `better_duck_core::udf` for usage and supported attribute options.
18#[proc_macro_attribute]
19pub fn duckdb_scalar(
20    attr: TokenStream,
21    item: TokenStream,
22) -> TokenStream {
23    let input = parse_macro_input!(item as ItemFn);
24    let original = input.clone();
25    match attrs::parse_scalar_attrs(attr).and_then(|attrs| scalar::expand(attrs, input)) {
26        Ok(expanded) => expanded.into(),
27        Err(err) => {
28            // Re-emit the original item alongside the error so the user gets one
29            // good diagnostic instead of a cascade of "cannot find function".
30            let mut out: TokenStream = quote::quote!(#original).into();
31            out.extend(TokenStream::from(err.to_compile_error()));
32            out
33        },
34    }
35}
36
37/// Registers a plain Rust function as a DuckDB table function.
38///
39/// See `better_duck_core::udf` for usage and supported attribute options.
40#[proc_macro_attribute]
41pub fn duckdb_table_function(
42    attr: TokenStream,
43    item: TokenStream,
44) -> TokenStream {
45    let input = parse_macro_input!(item as ItemFn);
46    let original = input.clone();
47    match crate::attrs::parse_table_attrs(attr).and_then(|attrs| crate::table::expand(attrs, input))
48    {
49        Ok(expanded) => expanded.into(),
50        Err(err) => {
51            let mut out: TokenStream = quote::quote!(#original).into();
52            out.extend(TokenStream::from(err.to_compile_error()));
53            out
54        },
55    }
56}