ddd_toolkit_macro/lib.rs
1//! **English:**<br>
2//! Derive value objects, identity-based entities, domain-event markers,
3//! and aggregate event queues for `ddd-toolkit-core`.
4//!
5//! Add both `ddd-toolkit-macro` and `ddd-toolkit-core` to your dependencies.
6//! Expansion resolves the core package by name, including renamed dependencies;
7//! a facade dependency alone is not resolved. These macros generate implementations
8//! at compile time, not runtime synchronization or persistence.
9//!
10//! Use [`ValueObject`] for field-based equality, [`Entity`] for identity-based
11//! equality, [`DomainEvent`] for event types, and [`AggregateRoot`] for a draining
12//! event queue. Do not separately derive traits that a macro already implements.
13//!
14//! **日本語:**<br>
15//! `ddd-toolkit-core` 向けに、値オブジェクト、識別子で比較する
16//! エンティティ、ドメインイベントのマーカー、集約のイベントキューを導出します。
17//!
18//! 依存関係には `ddd-toolkit-macro` と `ddd-toolkit-core` の両方が必要です。
19//! コアのパッケージ名から参照先を解決するため依存の別名に対応しますが、
20//! ファサードだけの依存は解決しません。実装をコンパイル時に生成するもので、
21//! 実行時の同期や永続化は行いません。
22//!
23//! フィールドの値で比較する型には [`ValueObject`]、識別子で比較する型には
24//! [`Entity`]、イベント型には [`DomainEvent`]、イベントを取り出して空にする
25//! キューには [`AggregateRoot`] を使います。生成済みのトレイトを重複して導出しないでください。
26//!
27//! # Example / 使用例
28//!
29//! ```rust
30//! use ddd_toolkit_macro::ValueObject;
31//!
32//! #[derive(ValueObject)]
33//! struct Quantity(u32);
34//!
35//! let quantity = Quantity::new(3);
36//! assert_eq!(quantity.as_inner(), &3);
37//! assert_eq!(quantity.into_inner(), 3);
38//! ```
39
40use proc_macro::TokenStream;
41use syn::parse_macro_input;
42
43mod aggregate_root;
44mod domain_event;
45mod entity;
46mod path;
47mod serde;
48mod value_object;
49
50/// **English:**<br>
51/// Implements `ddd_toolkit_core::ValueObject` and value-based
52/// `Debug`, `Clone`, `PartialEq`, `Eq`, and `Hash`, with corresponding field bounds.
53///
54/// Accepts nonempty named or tuple structs and nonempty enums, not unions or unit
55/// structs. A single-field struct exposes that field as `Inner`, `as_inner`, and
56/// `into_inner`; multi-field structs and enums use `Self` instead. Structs get
57/// `new` with fields in declaration order. Multi-field structs also get borrowed
58/// accessors named after fields, or `field_0`, `field_1`, etc. for tuple fields.
59/// Enums get `new_<variant>`, `is_<variant>`, and `as_<variant>`, using the fully
60/// lowercased variant name (not snake case). Variant accessors return `None` for
61/// another variant, `Some(())` for unit variants, or a tuple of field references.
62/// Lowercased variant names must be distinct; generated names must not collide
63/// with other methods or field accessors.
64///
65/// `#[value_object(trait_only)]` generates only the domain trait implementation,
66/// with the same `Inner` mapping but no inherent methods, constructors, standard
67/// traits, or extra bounds. It preserves handwritten APIs and cannot be combined
68/// with `validate`, `error`, or `serde`. It does not enforce invariants on public
69/// fields, direct enum construction, or independently implemented deserialization.
70///
71/// `#[value_object(validate = path, error = ErrorType)]` replaces `new` with
72/// `try_new` (or `try_new_<variant>`). Both options are required together. The
73/// validator receives `&Inner` for a single-field struct and `&Self` otherwise,
74/// returns `Result<(), ErrorType>`, and runs before the constructor returns the
75/// value. Its error is propagated; its panics are not caught. Validated struct
76/// fields cannot be unrestricted `pub`. Restricted visibility, direct construction
77/// inside the defining module, and enum variants can still bypass validation.
78///
79/// `#[value_object(serde)]` additionally generates serialization through the core
80/// crate's serde re-export; enable the core crate's `serde` feature. Single-field
81/// structs serialize as their inner value, named structs as structs, tuple structs
82/// as tuples, and enums as externally tagged variants by default. Supported
83/// container/variant/field `#[serde(...)]` attributes are delegated to Serde derive;
84/// unsupported attributes (including container conversions/default) are rejected.
85/// Single-field tuple variants
86/// use Serde's newtype format; other tuple variants use tuple format.
87/// Deserialization runs validation when configured,
88/// mapping its errors to `value object validation failed`. Serialization generation
89/// is selected by this attribute, not by a feature on the macro crate.
90/// Invalid shapes, duplicate or unknown options, and missing core dependencies
91/// produce compile errors; field types must satisfy the generated trait bounds.
92///
93/// **日本語:**<br>
94/// `ddd_toolkit_core::ValueObject` と値に基づく `Debug`、`Clone`、
95/// `PartialEq`、`Eq`、`Hash` を、各フィールドに必要な境界付きで実装します。
96///
97/// 空でない名前付き・タプル構造体と列挙型に対応し、共用体やユニット構造体は拒否します。
98/// 単一フィールド構造体の `Inner`、`as_inner`、`into_inner` はそのフィールドを扱い、
99/// 複数フィールド構造体と列挙型では `Self` を扱います。構造体には宣言順の引数を取る
100/// `new` を生成します。複数フィールドの場合は名前付きフィールド名、またはタプルの
101/// `field_0`、`field_1` などの名前で借用アクセサーも生成します。
102/// 列挙型にはバリアント名をすべて小文字にした(snake case ではない)接尾辞で
103/// `new_<variant>`、`is_<variant>`、`as_<variant>` を生成します。
104/// バリアントアクセサーは不一致なら `None`、ユニットなら `Some(())`、それ以外は
105/// フィールド参照のタプルを返します。小文字化した名前は一意である必要があり、
106/// 生成する名前を他のメソッドやフィールドアクセサーと衝突させないでください。
107///
108/// `#[value_object(trait_only)]` は同じ `Inner` 対応のドメイントレイト実装だけを
109/// 生成し、固有メソッド、コンストラクター、標準トレイト、追加の境界は生成しません。
110/// 手書きの API を維持でき、`validate`、`error`、`serde` とは併用できません。
111/// 公開フィールド、列挙型の直接構築、別途実装された逆直列化の不変条件は保証しません。
112///
113/// `#[value_object(validate = path, error = ErrorType)]` は `new` を `try_new`
114/// (列挙型では `try_new_<variant>`)に置き換えます。両オプションの同時指定が必要です。
115/// 検証関数は単一フィールドなら `&Inner`、それ以外なら `&Self` を受け取り、
116/// `Result<(), ErrorType>` を返します。値を返す前に検証し、エラーを伝播します。
117/// 検証関数のパニックは捕捉しません。検証付き構造体のフィールドは無制限の `pub` に
118/// できませんが、制限付き公開、定義モジュール内の直接構築、列挙型のバリアントからは
119/// 検証を迂回できます。
120///
121/// `#[value_object(serde)]` はコアの serde 再公開を使う直列化実装も生成します。
122/// コアの `serde` feature を有効にしてください。単一フィールドは内包値、名前付き
123/// 構造体は構造体、タプル構造体はタプル、列挙型は外部タグ形式で直列化します。
124/// これらは既定の形式です。対応するコンテナー・バリアント・フィールドの
125/// `#[serde(...)]` 属性は Serde derive に委譲し、非対応の属性(コンテナーの
126/// 変換属性や default など)は拒否します。
127/// 単一フィールドのタプルバリアントは Serde の newtype 形式、その他はタプル形式です。
128/// 逆直列化時も設定された検証を
129/// 実行し、検証エラーを `value object validation failed` に変換します。
130/// 直列化の生成はマクロクレートの feature ではなく、この属性で選択します。
131/// 非対応の形状、重複・未知のオプション、コア依存の欠落はコンパイルエラーになります。
132/// フィールド型は生成するトレイトの境界を満たす必要があります。
133///
134/// # Example / 使用例
135///
136/// ```rust
137/// use ddd_toolkit_macro::ValueObject;
138///
139/// #[derive(ValueObject)]
140/// #[value_object(validate = positive, error = &'static str)]
141/// struct Quantity(u32);
142///
143/// fn positive(value: &u32) -> Result<(), &'static str> {
144/// if *value > 0 { Ok(()) } else { Err("zero quantity") }
145/// }
146///
147/// assert_eq!(Quantity::try_new(0), Err("zero quantity"));
148/// assert_eq!(Quantity::try_new(2).unwrap().into_inner(), 2);
149///
150/// #[derive(ValueObject)]
151/// enum Status { Pending, Ready(u32) }
152/// let status = Status::new_ready(7);
153/// assert_eq!(status.as_ready(), Some((&7,)));
154/// assert!(!status.is_pending());
155/// ```
156#[proc_macro_derive(ValueObject, attributes(value_object, serde))]
157pub fn derive_value_object(input: TokenStream) -> TokenStream {
158 let input = parse_macro_input!(input as syn::DeriveInput);
159 value_object::expand(input)
160 .unwrap_or_else(syn::Error::into_compile_error)
161 .into()
162}
163
164/// **English:**<br>
165/// Implements `ddd_toolkit_core::Entity`, a borrowed inherent `id()`
166/// accessor, and `PartialEq`, `Eq`, and `Hash` using only the identifier field.
167///
168/// Requires a named-field struct with exactly one `#[entity(id)]` field. Other
169/// fields do not participate in comparison or hashing; identifier types must
170/// implement the corresponding traits. By default no constructor or validation
171/// is generated. Non-struct inputs, misplaced flags, missing or multiple identifier
172/// fields, unknown options, and missing core dependencies cause compile errors.
173///
174/// `#[entity(validate = path, error = ErrorType)]` generates `try_new` taking all
175/// fields in declaration order, including the supplied ID. The validator receives
176/// `&Self` (even for one field) and returns `Result<(), ErrorType>`; errors and
177/// panics propagate. Unrestricted `pub` fields are rejected. Direct construction
178/// in the defining module, restricted visibility, and handwritten mutations can
179/// still bypass validation; mutation methods must preserve invariants themselves.
180///
181/// `#[entity(serde)]` generates `Serialize` and `Deserialize` using the core
182/// crate's serde re-export; enable the core or facade `serde` feature. All fields
183/// participate, in struct format by default even for an ID-only entity. With
184/// validation configured, deserialization runs the same validator as `try_new`, mapping failures to
185/// `entity validation failed` without exposing the validator error. These paths
186/// only construct supplied state: they do not generate IDs or creation events.
187/// Use separate DTOs when persistence or wire formats differ from the domain model.
188/// Supported field/container `#[serde(...)]` attributes are delegated to Serde
189/// derive. Unsupported attributes, including container conversions/default, are rejected.
190///
191/// `#[entity(trait_only)]` generates only the domain trait implementation. It
192/// still requires `#[entity(id)]`, but adds no inherent `id()`, standard traits,
193/// or extra bounds, so handwritten accessors and equality semantics are preserved.
194/// It cannot be combined with `validate`, `error`, or `serde`.
195///
196/// **日本語:**<br>
197/// `ddd_toolkit_core::Entity` と識別子を借用する固有の `id()`、
198/// 識別子フィールドだけを使う `PartialEq`、`Eq`、`Hash` を実装します。
199///
200/// 名前付き構造体に `#[entity(id)]` フィールドがちょうど一つ必要です。
201/// 他のフィールドは比較やハッシュに使いません。識別子型は対応するトレイトを
202/// 実装する必要があります。既定ではコンストラクターや検証は生成しません。
203/// 構造体以外、フラグの誤配置、識別子の欠落・複数指定、未知のオプション、
204/// コア依存の欠落はコンパイルエラーになります。
205///
206/// `#[entity(validate = path, error = ErrorType)]` は ID を含む全フィールドを
207/// 宣言順に受け取る `try_new` を生成します。検証関数は単一フィールドでも
208/// `&Self` を受け取り、`Result<(), ErrorType>` を返します。エラーとパニックは
209/// 伝播します。無制限の `pub` フィールドは禁止しますが、定義モジュール内の
210/// 直接構築、制限付き公開、手書きの変更処理では検証を迂回できるため、
211/// 状態変更メソッド自身でも不変条件を維持してください。
212///
213/// `#[entity(serde)]` はコアの serde 再公開を使って `Serialize` と `Deserialize`
214/// を生成します。コアまたはファサードの `serde` feature が必要です。全フィールドを
215/// 対象とし、既定では ID のみでも構造体形式です。検証付きの逆直列化は
216/// `try_new` と同じ検証を実行し、
217/// 検証エラーの内容を公開せず `entity validation failed` に変換します。
218/// 指定された状態を構築するだけで、ID の生成や作成イベントの発生は行いません。
219/// 永続化・通信形式がドメインモデルと異なる場合は DTO を分けてください。
220/// 対応するフィールド・コンテナーの `#[serde(...)]` 属性は Serde derive に委譲し、
221/// 非対応の属性(コンテナーの変換属性や default など)は拒否します。
222///
223/// `#[entity(trait_only)]` はドメイントレイト実装だけを生成します。
224/// `#[entity(id)]` は引き続き必要ですが、固有の `id()`、標準トレイト、追加の
225/// 境界は生成しないため、手書きのアクセサーと等価性の意味を維持できます。
226/// `validate`、`error`、`serde` との併用はできません。
227///
228/// # Example / 使用例
229///
230/// ```rust
231/// use ddd_toolkit_macro::Entity;
232///
233/// #[derive(Entity)]
234/// struct Order {
235/// #[entity(id)]
236/// id: u64,
237/// total: u32,
238/// }
239/// let first = Order { id: 1, total: 10 };
240/// let updated = Order { id: 1, total: 20 };
241/// assert!(first == updated);
242/// assert_eq!(updated.id(), &1);
243///
244/// #[derive(Entity)]
245/// #[entity(validate = check, error = &'static str)]
246/// struct Stock {
247/// #[entity(id)]
248/// id: u64,
249/// reserved: u32,
250/// total: u32,
251/// }
252/// fn check(stock: &Stock) -> Result<(), &'static str> {
253/// if stock.reserved <= stock.total { Ok(()) } else { Err("over-reserved") }
254/// }
255/// assert!(Stock::try_new(1, 5, 3).is_err());
256/// assert_eq!(Stock::try_new(1, 2, 3).unwrap().id(), &1);
257/// ```
258#[proc_macro_derive(Entity, attributes(entity, serde))]
259pub fn derive_entity(input: TokenStream) -> TokenStream {
260 let input = parse_macro_input!(input as syn::DeriveInput);
261 entity::expand(input)
262 .unwrap_or_else(syn::Error::into_compile_error)
263 .into()
264}
265
266/// **English:**<br>
267/// Implements the empty `ddd_toolkit_core::DomainEvent` marker for
268/// a struct or enum, preserving its generic parameters and where clause.
269///
270/// Does not add methods, serialization, `Send`, or `Sync` bounds. Event contents
271/// and delivery remain the caller's responsibility. Unions and missing core
272/// dependencies produce compile errors.
273///
274/// **日本語:**<br>
275/// 構造体または列挙型に、空の `ddd_toolkit_core::DomainEvent`
276/// マーカーを実装し、ジェネリック引数と where 節を維持します。
277///
278/// メソッド、直列化、`Send`・`Sync` 境界は追加しません。イベントの内容と配信は
279/// 呼び出し側が管理します。共用体やコア依存の欠落はコンパイルエラーになります。
280///
281/// # Example / 使用例
282///
283/// ```rust
284/// use ddd_toolkit_macro::DomainEvent;
285///
286/// #[derive(DomainEvent)]
287/// enum OrderEvent { Placed { order_id: u64 }, Cancelled }
288/// fn accept_event(_: impl ddd_toolkit_core::DomainEvent) {}
289/// accept_event(OrderEvent::Placed { order_id: 1 });
290/// ```
291#[proc_macro_derive(DomainEvent)]
292pub fn derive_domain_event(input: TokenStream) -> TokenStream {
293 let input = parse_macro_input!(input as syn::DeriveInput);
294 domain_event::expand(input)
295 .unwrap_or_else(syn::Error::into_compile_error)
296 .into()
297}
298
299/// **English:**<br>
300/// Implements `ddd_toolkit_core::AggregateRoot` using a struct's
301/// `#[aggregate(events)]` vector as its pending event queue.
302///
303/// Requires a named-field struct that already implements `ddd_toolkit_core::Entity`
304/// (for example via [`Entity`]) and exactly one marked field spelled `Vec<Event>`
305/// or `std::vec::Vec<Event>`. Type aliases and other vector paths are not accepted;
306/// `Event` must implement `ddd_toolkit_core::DomainEvent` (see [`DomainEvent`]).
307/// `record_event` appends with `Vec::push`, preserving insertion order, and may
308/// allocate. `pull_events` moves out the vector with `core::mem::take`, leaving an
309/// empty queue; repeated pulls return empty vectors until another event is recorded.
310/// These are trait methods, not inherent methods; import the core trait to call
311/// them. Both require exclusive mutable access, with no locking, event publication,
312/// persistence, or domain-state update generated. Vector growth has the usual
313/// allocation and capacity limits of `Vec::push`.
314/// Unsupported shapes, missing or duplicate queues, unknown or valued flags,
315/// missing trait implementations, and missing core dependencies fail to compile.
316///
317/// **日本語:**<br>
318/// 構造体の `#[aggregate(events)]` ベクターを未処理イベントキュー
319/// として `ddd_toolkit_core::AggregateRoot` を実装します。
320///
321/// `ddd_toolkit_core::Entity` を実装済みの名前付き構造体(例: [`Entity`] による導出)
322/// と、`Vec<Event>` または `std::vec::Vec<Event>` と記述されたキューフィールドが
323/// ちょうど一つ必要です。型エイリアスや他のベクターパスは受け付けません。
324/// `Event` は `ddd_toolkit_core::DomainEvent` を実装する必要があります([`DomainEvent`])。
325/// `record_event` は `Vec::push` で挿入順に追加し、メモリを確保する場合があります。
326/// `pull_events` は `core::mem::take` でベクターを取り出し、キューを空にします。
327/// 次の記録まで再度取り出しても空のベクターを返します。固有メソッドではなくトレイト
328/// メソッドなので、呼び出すにはコアのトレイトをインポートしてください。
329/// どちらも排他的な可変アクセスを要求し、ロック、イベント配信、永続化、ドメイン状態の
330/// 更新は生成しません。キューの拡張には `Vec::push` と同じメモリ確保・容量制限があります。
331/// 非対応の形状、キューの欠落・重複、未知または値付きフラグ、必要なトレイト実装や
332/// コア依存の欠落はコンパイルエラーになります。
333///
334/// # Example / 使用例
335///
336/// ```rust
337/// use ddd_toolkit_core::AggregateRoot as _;
338/// use ddd_toolkit_macro::{AggregateRoot, DomainEvent, Entity};
339///
340/// #[derive(DomainEvent)]
341/// struct Placed;
342///
343/// #[derive(Entity, AggregateRoot)]
344/// struct Order {
345/// #[entity(id)]
346/// id: u64,
347/// #[aggregate(events)]
348/// events: Vec<Placed>,
349/// }
350/// let mut order = Order { id: 1, events: Vec::new() };
351/// order.record_event(Placed);
352/// assert_eq!(order.pull_events().len(), 1);
353/// assert!(order.pull_events().is_empty());
354/// ```
355#[proc_macro_derive(AggregateRoot, attributes(aggregate))]
356pub fn derive_aggregate_root(input: TokenStream) -> TokenStream {
357 let input = parse_macro_input!(input as syn::DeriveInput);
358 aggregate_root::expand(input)
359 .unwrap_or_else(syn::Error::into_compile_error)
360 .into()
361}
362
363#[cfg(test)]
364mod expansion_tests;