Skip to main content

laminate_derive/
lib.rs

1//! Derive macros for the laminate data shaping library.
2//!
3//! Provides `#[derive(Laminate)]` for progressive deserialization and
4//! `#[derive(ToolDefinition)]` for JSON schema generation from Rust structs.
5
6use proc_macro::TokenStream;
7use syn::{parse_macro_input, DeriveInput};
8
9mod expand;
10mod tool_def;
11
12/// Derive macro for progressive data shaping.
13///
14/// Generates deserialization logic that operates on an intermediate
15/// `HashMap<String, serde_json::Value>`, enabling coercion, overflow capture,
16/// and mode-dependent behavior.
17///
18/// # Attributes
19///
20/// - `#[laminate(overflow)]` — Captures unrecognized fields. Field must be `HashMap<String, serde_json::Value>`.
21/// - `#[laminate(rename = "x")]` — Deserialize from a different JSON key.
22/// - `#[laminate(default)]` — Use `Default::default()` if missing or null.
23/// - `#[laminate(coerce)]` — Apply type coercion rules from the coercion table.
24///
25/// # Example
26///
27/// ```ignore
28/// use laminate::Laminate;
29///
30/// #[derive(Debug, Laminate)]
31/// pub struct Config {
32///     #[laminate(coerce)]
33///     pub port: u16,
34///
35///     #[laminate(default)]
36///     pub debug: bool,
37///
38///     #[laminate(overflow)]
39///     pub extra: HashMap<String, serde_json::Value>,
40/// }
41/// ```
42#[proc_macro_derive(Laminate, attributes(laminate))]
43pub fn derive_laminate(input: TokenStream) -> TokenStream {
44    let input = parse_macro_input!(input as DeriveInput);
45    expand::expand_laminate(input)
46        .unwrap_or_else(|err| err.to_compile_error())
47        .into()
48}
49
50/// Derive macro for generating LLM tool definition JSON schemas.
51///
52/// Generates a `tool_definition()` method that returns a `serde_json::Value`
53/// matching the tool definition format expected by Anthropic, OpenAI, and
54/// other LLM APIs.
55///
56/// # Attributes
57///
58/// - `#[tool(name = "x")]` — Override the tool name (defaults to snake_case struct name)
59/// - `#[tool(description = "x")]` — Tool description sent to the LLM
60/// - `#[tool(rename = "x")]` — Use a different parameter name in the schema
61///
62/// # Example
63///
64/// ```ignore
65/// use laminate::ToolDefinition;
66///
67/// /// Get current weather for a city
68/// #[derive(ToolDefinition)]
69/// struct GetWeather {
70///     /// The city to look up
71///     city: String,
72///     /// Temperature units (celsius or fahrenheit)
73///     units: Option<String>,
74/// }
75///
76/// let schema = GetWeather::tool_definition();
77/// // Returns: {"name": "get_weather", "description": "Get current weather for a city",
78/// //   "input_schema": {"type": "object", "properties": {"city": {"type": "string",
79/// //   "description": "The city to look up"}, ...}, "required": ["city"]}}
80/// ```
81#[proc_macro_derive(ToolDefinition, attributes(tool))]
82pub fn derive_tool_definition(input: TokenStream) -> TokenStream {
83    let input = parse_macro_input!(input as DeriveInput);
84    tool_def::expand_tool_definition(input)
85        .unwrap_or_else(|err| err.to_compile_error())
86        .into()
87}