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