Skip to main content

struct_mapper_derive/
lib.rs

1//! # struct-mapper-derive
2//!
3//! Procedural macro crate for `struct-mapper`.
4//! Provides `#[derive(MapFrom)]` and `#[derive(TryMapFrom)]` to auto-generate
5//! `impl From<Source> for Target` and `impl TryFrom<Source> for Target`.
6//!
7//! **Do not depend on this crate directly.** Use `struct-mapper` instead.
8
9use proc_macro::TokenStream;
10use syn::{parse_macro_input, DeriveInput};
11
12mod codegen;
13mod error;
14mod field_match;
15mod parse;
16
17/// Derive macro that generates `impl From<Source> for Target` by mapping fields.
18///
19/// # Usage
20///
21/// ```rust,ignore
22/// use struct_mapper::MapFrom;
23///
24/// struct UserEntity {
25///     name: String,
26///     email: String,
27/// }
28///
29/// #[derive(MapFrom)]
30/// #[map_from(UserEntity)]
31/// struct UserResponse {
32///     name: String,
33///     email: String,
34/// }
35///
36/// // Now you can do:
37/// let entity = UserEntity { name: "Alice".into(), email: "a@b.com".into() };
38/// let response: UserResponse = entity.into();
39/// ```
40///
41/// # Field Attributes
42///
43/// - `#[map(from = "source_field")]` — Map from a differently-named source field
44/// - `#[map(skip, default)]` — Skip this field, use `Default::default()`
45/// - `#[map(into)]` — Call `.into()` on the source field value
46/// - `#[map(with = "path::to::fn")]` — Apply a custom conversion function
47#[proc_macro_derive(MapFrom, attributes(map_from, map))]
48pub fn derive_map_from(input: TokenStream) -> TokenStream {
49    let input = parse_macro_input!(input as DeriveInput);
50
51    match codegen::expand_map_from(&input) {
52        Ok(tokens) => tokens.into(),
53        Err(err) => err.to_compile_error().into(),
54    }
55}
56
57/// Derive macro that generates `impl TryFrom<Source> for Target` by mapping fields.
58///
59/// Use this when one or more field conversions can fail (e.g., type narrowing,
60/// parsing, validation). The generated implementation returns
61/// `Result<Self, struct_mapper::MapError>`.
62///
63/// # Usage
64///
65/// ```rust,ignore
66/// use struct_mapper::TryMapFrom;
67///
68/// struct RawInput {
69///     count: i64,
70///     name: String,
71/// }
72///
73/// #[derive(TryMapFrom)]
74/// #[try_map_from(RawInput)]
75/// struct ValidInput {
76///     #[map(try_into)]
77///     count: u32,     // i64 -> u32 can fail
78///     name: String,   // direct (infallible)
79/// }
80///
81/// // Now you can do:
82/// let raw = RawInput { count: 42, name: "Alice".into() };
83/// let valid: ValidInput = raw.try_into().unwrap();
84/// ```
85///
86/// # Field Attributes
87///
88/// All `MapFrom` attributes work here, plus:
89///
90/// - `#[map(try_into)]` — Call `.try_into()` on the source field (fallible)
91/// - `#[map(try_with = "path::to::fn")]` — Apply a fallible conversion function
92#[proc_macro_derive(TryMapFrom, attributes(try_map_from, map))]
93pub fn derive_try_map_from(input: TokenStream) -> TokenStream {
94    let input = parse_macro_input!(input as DeriveInput);
95
96    match codegen::expand_try_map_from(&input) {
97        Ok(tokens) => tokens.into(),
98        Err(err) => err.to_compile_error().into(),
99    }
100}