swift_mt_message_macros/
lib.rs

1//! # Swift MT Message Macros - Clean Rewrite
2//!
3//! This crate provides derive macros for generating SWIFT MT message parsing and serialization code.
4//! The implementation focuses on clean architecture, robust error handling, and high performance.
5
6use proc_macro::TokenStream;
7
8// Module declarations
9mod ast;
10mod codegen;
11mod error;
12mod format;
13mod utils;
14
15use error::MacroError;
16use utils::serde_attributes::add_serde_attributes_to_optional_fields;
17
18/// Derive macro for SwiftField trait implementation
19///
20/// Generates parsing, serialization, and validation code for SWIFT field structures.
21/// Supports component-based field definitions with format specifications.
22///
23/// ## Basic Usage
24///
25/// ### Simple Field
26/// ```logic
27/// use swift_mt_message_macros::SwiftField;
28/// use serde::{Deserialize, Serialize};
29///
30/// #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
31/// struct Field20 {
32///     #[component("16x")]
33///     reference: String,
34/// }
35/// ```
36///
37/// ### Multi-Component Field
38/// ```logic
39/// #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftField)]
40/// struct Field32A {
41///     #[component("6!n")]     // Date: YYMMDD
42///     date: String,
43///     #[component("3!a")]     // Currency: ISO code
44///     currency: String,
45///     #[component("15d")]     // Amount: decimal
46///     amount: f64,
47/// }
48/// ```
49///
50/// ### Enum Field (Multiple Variants)
51/// ```logic
52/// #[derive(Debug, Clone, PartialEq, Serialize, Deserialize, SwiftField)]
53/// enum Field50 {
54///     A(Field50A),
55///     F(Field50F),
56///     K(Field50K),
57/// }
58/// ```
59///
60/// ## Format Specifications
61///
62/// The `#[component("format")]` attribute supports SWIFT format specifications:
63///
64/// - **Fixed length**: `3!a` (exactly 3 alphabetic chars)
65/// - **Variable length**: `35x` (up to 35 any chars)
66/// - **Optional**: `[/34x]` (optional account with slash prefix)
67/// - **Repetitive**: `4*35x` (up to 4 lines of 35 chars each)
68/// - **Decimal**: `15d` (decimal number up to 15 digits)
69///
70/// ## Generated Methods
71///
72/// The macro generates these methods for the SwiftField trait:
73/// - `parse(value: &str) -> Result<Self>` - Parse from SWIFT format string
74/// - `to_swift_string(&self) -> String` - Convert to SWIFT format string
75/// - `format_spec() -> &'static str` - Return format specification
76#[proc_macro_derive(SwiftField, attributes(component))]
77pub fn derive_swift_field(input: TokenStream) -> TokenStream {
78    match derive_swift_field_impl(input) {
79        Ok(result) => result,
80        Err(error) => error.to_compile_error().into(),
81    }
82}
83
84/// Derive macro for SwiftMessage trait implementation
85///
86/// Generates message-level parsing, validation, and field management code.
87/// Supports field specifications and validation rules for complete SWIFT message types.
88///
89/// ## Basic Usage
90///
91/// ```logic
92/// use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
93/// use serde::{Deserialize, Serialize};
94/// use crate::fields::*;
95///
96/// #[serde_swift_fields]
97/// #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
98/// struct MT103 {
99///     // Mandatory fields (no Option wrapper)
100///     #[field("20")]
101///     field_20: Field20,
102///     
103///     #[field("32A")]
104///     field_32a: Field32A,
105///     
106///     // Optional fields (wrapped in Option)
107///     #[field("50A")]
108///     field_50a: Option<Field50A>,
109///     
110///     // Repetitive fields (wrapped in Vec)
111///     #[field("71A")]
112///     field_71a: Option<Vec<Field71A>>,
113/// }
114/// ```
115///
116/// ## Field Attributes
117///
118/// The `#[field("tag")]` attribute maps struct fields to SWIFT field tags:
119/// - `#[field("20")]` - Maps to SWIFT field 20
120/// - `#[field("32A")]` - Maps to SWIFT field 32A with option
121/// - Field tags must match the SWIFT standard exactly
122///
123/// ## Field Types
124///
125/// - **Mandatory**: `field_20: Field20` - Required field
126/// - **Optional**: `field_50: Option<Field50>` - Optional field  
127/// - **Repetitive**: `field_71a: Vec<Field71A>` - Multiple occurrences
128/// - **Optional Repetitive**: `field_71a: Option<Vec<Field71A>>` - Optional multiple
129///
130/// ## Generated Methods
131///
132/// The macro generates these methods for the SwiftMessageBody trait:
133/// - `message_type() -> &'static str` - Returns message type (e.g., "103")
134/// - `from_fields(fields: HashMap<String, Vec<String>>) -> Result<Self>` - Parse from field map
135/// - `to_fields(&self) -> HashMap<String, Vec<String>>` - Convert to field map
136/// - `required_fields() -> Vec<&'static str>` - List required field tags
137/// - `optional_fields() -> Vec<&'static str>` - List optional field tags
138#[proc_macro_derive(SwiftMessage, attributes(field, sequence, validation_rules))]
139pub fn derive_swift_message(input: TokenStream) -> TokenStream {
140    match derive_swift_message_impl(input) {
141        Ok(result) => result,
142        Err(error) => error.to_compile_error().into(),
143    }
144}
145
146/// Attribute macro for automatic serde field generation
147///
148/// Automatically adds appropriate serde attributes based on field configurations
149/// for clean JSON serialization without enum wrappers.
150///
151/// ## Usage
152///
153/// Apply this attribute to message structs before the derive attributes:
154///
155/// ```logic
156/// use swift_mt_message_macros::{SwiftMessage, serde_swift_fields};
157/// use serde::{Deserialize, Serialize};
158///
159/// #[serde_swift_fields]  // Apply this first
160/// #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, SwiftMessage)]
161/// struct MT103 {
162///     #[field("20")]
163///     field_20: Field20,
164/// }
165/// ```
166///
167/// This macro automatically:
168/// - Adds `#[serde(skip_serializing_if = "Option::is_none")]` to optional fields
169/// - Configures proper field naming for JSON output
170/// - Ensures clean serialization without enum variant wrappers
171#[proc_macro_attribute]
172pub fn serde_swift_fields(_args: TokenStream, input: TokenStream) -> TokenStream {
173    match serde_swift_fields_impl(input) {
174        Ok(result) => result,
175        Err(error) => error.to_compile_error().into(),
176    }
177}
178
179/// Internal implementation for SwiftField derive macro
180fn derive_swift_field_impl(input: TokenStream) -> Result<TokenStream, MacroError> {
181    let mut input: syn::DeriveInput = syn::parse(input)?;
182
183    // Add serde attributes to optional fields
184    add_serde_attributes_to_optional_fields(&mut input)?;
185
186    let definition = ast::FieldDefinition::parse(&input)?;
187    let tokens = codegen::field::generate_swift_field_impl(&definition)?;
188    Ok(tokens.into())
189}
190
191/// Internal implementation for SwiftMessage derive macro
192fn derive_swift_message_impl(input: TokenStream) -> Result<TokenStream, MacroError> {
193    let input = syn::parse(input)?;
194    let definition = ast::MessageDefinition::parse(&input)?;
195    let tokens = codegen::message::generate_swift_message_impl(&definition)?;
196    Ok(tokens.into())
197}
198
199/// Internal implementation for serde_swift_fields attribute macro
200fn serde_swift_fields_impl(input: TokenStream) -> Result<TokenStream, MacroError> {
201    let input = syn::parse(input)?;
202    let tokens = codegen::serde::generate_serde_attributes(&input)?;
203    Ok(tokens.into())
204}
205
206#[cfg(test)]
207mod tests {
208    // Note: We can't test procedural macro generation in unit tests
209    // The actual testing should be done through integration tests
210    // where the macro is used in a proper procedural macro environment.
211}