Skip to main content

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}