gear_mesh_derive/
lib.rs

1//! gear-mesh-derive: proc-macro for GearMesh derive
2//!
3//! このクレートは `#[derive(GearMesh)]` マクロを提供します。
4
5use proc_macro::TokenStream;
6use quote::quote;
7use syn::{DeriveInput, parse_macro_input};
8
9mod attributes;
10mod parser;
11
12use parser::parse_type;
13
14/// GearMesh derive macro
15///
16/// Rust型をTypeScriptに変換可能な中間表現に変換します。
17///
18/// # 属性
19///
20/// - `#[gear_mesh(branded)]`: Branded Typeとして生成
21/// - `#[gear_mesh(validate)]`: バリデーション関数を生成
22/// - `#[gear_mesh(bigint = "auto")]`: BigInt自動変換を有効化
23///
24/// # Example
25///
26/// ```ignore
27/// use gear_mesh::GearMesh;
28///
29/// #[derive(GearMesh)]
30/// #[gear_mesh(branded)]
31/// struct UserId(i32);
32///
33/// #[derive(GearMesh)]
34/// struct User {
35///     id: UserId,
36///     name: String,
37/// }
38/// ```
39#[proc_macro_derive(GearMesh, attributes(gear_mesh, validate))]
40pub fn derive_gear_mesh(input: TokenStream) -> TokenStream {
41    let input = parse_macro_input!(input as DeriveInput);
42
43    match parse_type(&input) {
44        Ok(gear_mesh_type) => {
45            let name = &input.ident;
46            let type_json = serde_json::to_string(&gear_mesh_type).unwrap_or_default();
47
48            let expanded = quote! {
49                impl ::gear_mesh::GearMeshExport for #name {
50                    fn gear_mesh_type() -> ::gear_mesh::GearMeshType {
51                        let json = #type_json;
52                        ::serde_json::from_str(json).expect("Failed to deserialize GearMeshType")
53                    }
54
55                    fn type_name() -> &'static str {
56                        stringify!(#name)
57                    }
58                }
59
60                // Register type with inventory for automatic collection
61                ::gear_mesh::inventory::submit! {
62                    ::gear_mesh::TypeInfo {
63                        get_type: || <#name as ::gear_mesh::GearMeshExport>::gear_mesh_type(),
64                        type_name: stringify!(#name),
65                    }
66                }
67            };
68
69            // If output path is specified, trigger automatic generation
70            let output_trigger = if let Some(output_path) = &gear_mesh_type.attributes.output_path {
71                quote! {
72                    // Trigger automatic type generation on first use
73                    const _: () = {
74                        ::gear_mesh::register_output(#output_path);
75                    };
76                }
77            } else {
78                quote! {}
79            };
80
81            let final_output = quote! {
82                #expanded
83                #output_trigger
84            };
85
86            TokenStream::from(final_output)
87        }
88        Err(err) => TokenStream::from(err.to_compile_error()),
89    }
90}