germanic_macros/lib.rs
1//! # GERMANIC Macros
2//!
3//! Proc-macro crate for the GERMANIC schema system.
4//!
5//! ## Architecture
6//!
7//! ```text
8//! ┌─────────────────────────────────────────────────────────────────┐
9//! │ MACRO PROCESSING PIPELINE │
10//! ├─────────────────────────────────────────────────────────────────┤
11//! │ │
12//! │ Rust Source Code │
13//! │ ┌─────────────────────────────────────────┐ │
14//! │ │ #[derive(GermanicSchema)] │ │
15//! │ │ #[germanic(schema_id = "...", ...)] │ │
16//! │ │ pub struct PracticeSchema { ... } │ │
17//! │ └─────────────────────────────────────────┘ │
18//! │ │ │
19//! │ ▼ │
20//! │ ┌─────────────────────────────────────────┐ │
21//! │ │ syn::parse() │ │
22//! │ │ Token Stream → DeriveInput (AST) │ │
23//! │ └─────────────────────────────────────────┘ │
24//! │ │ │
25//! │ ▼ │
26//! │ ┌─────────────────────────────────────────┐ │
27//! │ │ darling::FromDeriveInput │ │
28//! │ │ AST → SchemaOpts (typed data) │ │
29//! │ └─────────────────────────────────────────┘ │
30//! │ │ │
31//! │ ▼ │
32//! │ ┌─────────────────────────────────────────┐ │
33//! │ │ quote::quote!() │ │
34//! │ │ Typed Data → Rust Code │ │
35//! │ └─────────────────────────────────────────┘ │
36//! │ │ │
37//! │ ▼ │
38//! │ Generated Rust Code │
39//! │ ┌─────────────────────────────────────────┐ │
40//! │ │ impl GermanicSerialize for PracticeSchema│ │
41//! │ │ impl SchemaMetadata for PracticeSchema │ │
42//! │ │ impl Validate for PracticeSchema │ │
43//! │ └─────────────────────────────────────────┘ │
44//! │ │
45//! └─────────────────────────────────────────────────────────────────┘
46//! ```
47//!
48//! ## Usage
49//!
50//! ```rust,ignore
51//! use germanic_macros::GermanicSchema;
52//!
53//! #[derive(GermanicSchema)]
54//! #[germanic(schema_id = "de.gesundheit.praxis.v1")]
55//! pub struct PracticeSchema {
56//! #[germanic(required)]
57//! pub name: String,
58//!
59//! pub telefon: Option<String>,
60//! }
61//! ```
62
63// Proc-macro crates may ONLY export macros, no other items.
64// Therefore: private modules for implementation.
65mod schema;
66
67use proc_macro::TokenStream;
68use syn::{DeriveInput, parse_macro_input};
69
70/// # `#[derive(GermanicSchema)]`
71///
72/// Automatically generates implementations for GERMANIC schemas.
73///
74/// ## Struct-level Attributes
75///
76/// | Attribute | Type | Description |
77/// |----------|------|-------------|
78/// | `schema_id` | String | Unique schema ID (e.g. `"de.gesundheit.praxis.v1"`) |
79/// | `flatbuffer` | String | Path to FlatBuffer type (e.g. `"de::praxis::Praxis"`) |
80///
81/// ## Field-level Attributes
82///
83/// | Attribute | Type | Description |
84/// |----------|------|-------------|
85/// | `required` | Flag | Field must not be `None`/empty |
86/// | `default` | Value | Default value if not specified |
87///
88/// ## Generated Traits
89///
90/// 1. **`GermanicSerialize`**: Serialization to FlatBuffer bytes
91/// 2. **`SchemaMetadata`**: Schema ID and version
92/// 3. **`Validate`**: Validation of required fields
93///
94/// ## Example
95///
96/// ```rust,ignore
97/// #[derive(GermanicSchema, Deserialize)]
98/// #[germanic(
99/// schema_id = "de.gesundheit.praxis.v1",
100/// flatbuffer = "de::praxis::Praxis"
101/// )]
102/// pub struct PracticeSchema {
103/// #[germanic(required)]
104/// pub name: String,
105///
106/// #[germanic(required)]
107/// pub bezeichnung: String,
108///
109/// pub praxisname: Option<String>,
110///
111/// #[germanic(default = false)]
112/// pub privatpatienten: bool,
113/// }
114/// ```
115#[proc_macro_derive(GermanicSchema, attributes(germanic))]
116pub fn derive_germanic_schema(input: TokenStream) -> TokenStream {
117 // 1. Parse the token stream into an AST
118 // DeriveInput contains: Name, Generics, Attributes, Data (Struct/Enum)
119 let ast = parse_macro_input!(input as DeriveInput);
120
121 // 2. Delegate to implementation in schema module
122 // On error: Compiler error with meaningful message
123 schema::implement_germanic_schema(ast).unwrap_or_else(|error| error.write_errors().into())
124}