1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
use ;
use TokenStream;
use ;
/// A procedural macro that generates a function that parses a resource name into a tuple of typed segments.
///
/// Resource name format is documented in Google's AIP [1].
/// Ending segments can also be optional [2].
///
/// [1]: https://google.aip.dev/122
/// [2]: https://google.aip.dev/162
///
/// # Examples
///
/// ```
/// # use bomboni_request_derive::parse_resource_name;
/// let name = "users/42/projects/1337";
/// let parsed = parse_resource_name!({
/// "users": u32,
/// "projects": u64,
/// })(name);
/// assert_eq!(parsed, Some((42, 1337)));
/// ```
/// Derive macro for creating derived map types.
/// Derive macro for parsing request types.
///
/// This macro generates code for converting between different data representations.
/// It's commonly used for converting protobuf messages to domain models, but can
/// handle any type conversion scenario.
///
/// # Attributes
///
/// ## Struct-level attributes
///
/// - `source = "Type"` - Source type to parse from (required)
/// - `write = bool` - Generate write/conversion code back to source type
/// - `serialize_as = bool` - Generate Serialize for source type
/// - `deserialize_as = bool` - Generate Deserialize for source type
/// - `serde_as = bool` - Generate both Serialize and Deserialize for source type
/// - `request = {...}` - Mark as request message for error handling
/// - `tagged_union = {...}` - Create tagged union from oneof field
/// - `bomboni_crate = "path"` - Custom bomboni crate path
/// - `bomboni_proto_crate = "path"` - Custom `bomboni_proto` crate path
/// - `bomboni_request_crate = "path"` - Custom `bomboni_request` crate path
/// - `serde_crate = "path"` - Custom serde crate path
///
/// ## Field-level attributes
///
/// - `source = "field"` - Source field name to parse from
/// - `source_field = bool` - Source field name is same as target
/// - `skip = bool` - Skip parsing this field
/// - `keep = bool` - Keep field unchanged
/// - `keep_primitive = bool` - Keep primitive types unchanged
/// - `unspecified = bool` - Allow unspecified enum values
/// - `extract = {...}` - Custom extraction plan
/// - `wrapper = bool` - Parse protobuf wrapper types
/// - `oneof = bool` - Parse from oneof field
/// - `enumeration = bool` - Parse enum from i32
/// - `regex = "pattern"` - Validate with regex
/// - `timestamp = bool` - Parse protobuf timestamps
/// - `try_from = "path"` - Custom `TryFrom` conversion
/// - `convert = {...}` - Custom conversion functions
/// - `derive = {...}` - Use derived parsing
/// - `resource = {...}` - Parse resource fields
/// - `list_query = {...}` - Parse list query
/// - `search_query = {...}` - Parse search query
/// - `field_mask = {...}` - Parse field only if field mask allows it
///
/// # Examples
///
/// Basic usage:
///
/// ```rust,ignore
/// #[derive(Parse)]
/// #[parse(source = "proto::User")]
/// struct User {
/// #[parse(source = "user_name")]
/// name: String,
/// }
/// ```
///
/// With bidirectional conversion:
///
/// ```rust,ignore
/// #[derive(Parse)]
/// #[parse(source = "proto::User", write = true)]
/// struct User {
/// name: String,
/// email: Option<String>,
/// }
/// ```
///
/// Complex example with multiple features:
///
/// ```rust,ignore
/// #[derive(Parse)]
/// #[parse(source = "proto::UserMessage", write = true, serde_as = true)]
/// struct User {
/// #[parse(source = "user_id", try_from = "UserId::from_str")]
/// id: UserId,
///
/// #[parse(source = "user_name")]
/// name: String,
///
/// #[parse(source = "email_address", regex = r"[^@]+@[^@]+\.[^@]+")]
/// email: String,
///
/// #[parse(source = "created_timestamp", timestamp)]
/// created_at: OffsetDateTime,
///
/// #[parse(source = "status_code", enumeration)]
/// status: UserStatus,
///
/// #[parse(source = "profile_data", keep)]
/// metadata: HashMap<String, String>,
/// }
/// ```
///
/// Field mask example for update operations:
///
/// ```rust,ignore
/// #[derive(Parse)]
/// #[parse(source = "UpdateBookRequest", write = true)]
/// struct ParsedUpdateBookRequest {
/// #[parse(source = "book?.name", convert = book_id_convert)]
/// id: BookId,
/// #[parse(source = "book?.display_name", field_mask { field = book, mask = update_mask })]
/// display_name: Option<String>,
/// }
/// ```