• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2024 Google LLC.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 /// proto! enables the use of Rust struct initialization syntax to create
9 /// protobuf messages. The macro does its best to try and detect the
10 /// initialization of submessages, but it is only able to do so while the
11 /// submessage is being defined as part of the original struct literal.
12 /// Introducing an expression using () or {} as the value of a field will
13 /// require another call to this macro in order to return a submessage
14 /// literal.``` /*
15 /// Given the following proto definition
16 /// message Data {
17 ///     int32 number = 1;
18 ///     string letters = 2;
19 ///     Data nested = 3;
20 /// }
21 /// */
22 /// use protobuf::proto;
23 /// let message = proto!(Data {
24 ///     number: 42,
25 ///     letters: "Hello World",
26 ///     nested: Data {
27 ///         number: {
28 ///             let x = 100;
29 ///             x + 1
30 ///         }
31 ///     }
32 /// }); ```
33 #[macro_export]
34 macro_rules! proto {
35     ($msgtype:ty { $($tt:tt)* }) => {
36         $crate::proto_internal!($msgtype { $($tt)* })
37     }
38 }
39 
40 #[macro_export(local_inner_macros)]
41 #[doc(hidden)]
42 macro_rules! proto_internal {
43     // @merge rules are used to find a trailing ..expr on the message and call merge_from on it
44     // before the fields of the message are set.
45     (@merge $msg:ident $ident:ident : $expr:expr, $($rest:tt)*) => {
46         proto_internal!(@merge $msg $($rest)*);
47     };
48 
49     (@merge $msg:ident $ident:ident : $expr:expr) => {
50     };
51 
52     (@merge $msg:ident ..$expr:expr) => {
53         $crate::MergeFrom::merge_from(&mut $msg, $expr);
54     };
55 
56     // @msg rules are used to set the fields of the message. There is a lot of duplication here
57     // because we need to parse the message type using a :: separated list of identifiers.
58     // nested message and trailing fields
59     (@msg $msg:ident $submsg:ident : $($msgtype:ident)::+ { $($value:tt)* }, $($rest:tt)*) => {
60         proto_internal!(@msg $msg $submsg : $($msgtype)::+ { $($value)* });
61         proto_internal!(@msg $msg $($rest)*);
62     };
63     // nested message with leading :: on type and trailing fields
64     (@msg $msg:ident $submsg:ident : ::$($msgtype:ident)::+ { $($value:tt)* }, $($rest:tt)*) => {
65         proto_internal!(@msg $msg $submsg : ::$($msgtype)::+ { $($value)* });
66         proto_internal!(@msg $msg $($rest)*);
67     };
68 
69     // nested message using __
70     (@msg $msg:ident $submsg:ident : __ { $($value:tt)* }) => {
71         {
72             let mut $msg = $crate::__internal::paste!($msg.[<$submsg _mut>]());
73             proto_internal!(@merge $msg $($value)*);
74             proto_internal!(@msg $msg $($value)*);
75         }
76     };
77     // nested message
78     (@msg $msg:ident $submsg:ident : $($msgtype:ident)::+ { $($value:tt)* }) => {
79         {
80             let mut $msg: <$($msgtype)::+ as $crate::MutProxied>::Mut<'_> = $crate::__internal::paste!($msg.[<$submsg _mut>]());
81             proto_internal!(@merge $msg $($value)*);
82             proto_internal!(@msg $msg $($value)*);
83         }
84     };
85     // nested message with leading ::
86     (@msg $msg:ident $submsg:ident : ::$($msgtype:ident)::+ { $($value:tt)* }) => {
87         {
88             let mut $msg: <::$($msgtype)::+ as $crate::MutProxied>::Mut<'_> = $crate::__internal::paste!($msg.[<$submsg _mut>]());
89             proto_internal!(@merge $msg $($value)*);
90             proto_internal!(@msg $msg $($value)*);
91         }
92     };
93 
94     // field with array literal and trailing fields
95     (@msg $msg:ident $ident:ident : [$($elems:tt)*], $($rest:tt)*) => {
96         proto_internal!(@msg $msg $ident : [$($elems)*]);
97         proto_internal!(@msg $msg $($rest)*);
98     };
99     // field with array literal, calls out to @array to look for nested messages
100     (@msg $msg:ident $ident:ident : [$($elems:tt)*]) => {
101         {
102             let _repeated = $crate::__internal::paste!($msg.[<$ident>]());
103             let elems = proto_internal!(@array $msg _repeated [] $($elems)*);
104             $crate::__internal::paste!($msg.[<set_ $ident>](elems.into_iter()));
105         }
106     };
107 
108     // @array searches through an array literal for nested messages.
109     // If a message is found then we recursively call the macro on it to set the fields.
110     // This will create an array literal of owned messages to be used while setting the field.
111     // For primitive types they should just be passed through as an $expr.
112     // The array literal is constructed recursively, so the [] case has to be handled separately so
113     // that we can properly insert commas. This leads to a lot of duplication.
114 
115     // Message nested in array literal with trailing array items
116     (@array $msg:ident $repeated:ident [$($vals:expr),+] __ { $($value:tt)* }, $($rest:tt)*) => {
117         proto_internal!(@array $msg $repeated [
118                 $($vals),+ ,
119                 {
120                     let mut $msg = $crate::get_repeated_default_value($crate::__internal::Private, $repeated);
121                     proto_internal!(@merge $msg $($value)*);
122                     proto_internal!(@msg $msg $($value)*);
123                     $msg
124                 }
125             ] $($rest)*)
126     };
127 
128     // Message nested in [] literal
129     (@array $msg:ident $repeated:ident [$($vals:expr),+] __ { $($value:tt)* }) => {
130         [
131             $($vals),+ ,
132             {
133                 let mut $msg = $crate::get_repeated_default_value($crate::__internal::Private, $repeated);
134                 proto_internal!(@merge $msg $($value)*);
135                 proto_internal!(@msg $msg $($value)*);
136                 $msg
137             }
138         ]
139     };
140 
141     // Message nested in array literal with trailing array items
142     (@array $msg:ident $repeated:ident [] __ { $($value:tt)* }, $($rest:tt)*) => {
143         proto_internal!(@array $msg $repeated [
144                 {
145                     let mut $msg = $crate::get_repeated_default_value($crate::__internal::Private, $repeated);
146                     proto_internal!(@merge $msg $($value)*);
147                     proto_internal!(@msg $msg $($value)*);
148                     $msg
149                 }
150             ] $($rest)*)
151     };
152 
153     // Message nested in [] literal
154     (@array $msg:ident $repeated:ident [] __ { $($value:tt)* }) => {
155         [
156             {
157                 let mut $msg = $crate::get_repeated_default_value($crate::__internal::Private, $repeated);
158                 proto_internal!(@merge $msg $($value)*);
159                 proto_internal!(@msg $msg $($value)*);
160                 $msg
161             }
162         ]
163     };
164 
165     // End of __ repeated, now we need to handle named types
166 
167     // Message nested in array literal with trailing array items
168     (@array $msg:ident $repeated:ident [$($vals:expr),+] $($msgtype:ident)::+ { $($value:tt)* }, $($rest:tt)*) => {
169         proto_internal!(@array $msg $repeated [
170                 $($vals),+ ,
171                 {
172                     let mut $msg = $($msgtype)::+::new();
173                     proto_internal!(@merge $msg $($value)*);
174                     proto_internal!(@msg $msg $($value)*);
175                     $msg
176                 }
177             ] $($rest)*)
178     };
179     // Message nested in [] literal with leading :: on type and trailing array items
180     (@array $msg:ident $repeated:ident [$($vals:expr),+] ::$($msgtype:ident)::+ { $($value:tt)* }, $($rest:tt)*) => {
181         proto_internal!(@array $msg $repeated [
182                 $($vals),+ ,
183                 {
184                     let mut $msg = ::$($msgtype)::+::new();
185                     proto_internal!(@merge $msg $($value)*);
186                     proto_internal!(@msg $msg $($value)*);
187                     $msg
188                 }
189             ] $($rest)*)
190     };
191     // Message nested in [] literal
192     (@array $msg:ident $repeated:ident [$($vals:expr),+] $($msgtype:ident)::+ { $($value:tt)* }) => {
193         [
194             $($vals),+ ,
195             {
196                 let mut $msg = $($msgtype)::+::new();
197                 proto_internal!(@merge $msg $($value)*);
198                 proto_internal!(@msg $msg $($value)*);
199                 $msg
200             }
201         ]
202     };
203     // Message nested in [] literal with leading :: on type
204     (@array $msg:ident $repeated:ident [$($vals:expr),+] ::$($msgtype:ident)::+ { $($value:tt)* }) => {
205         [
206             $($vals),+ ,
207             {
208                 let mut $msg = ::$($msgtype)::+::new();
209                 proto_internal!(@merge $msg $($value)*);
210                 proto_internal!(@msg $msg $($value)*);
211                 $msg
212             }
213         ]
214     };
215 
216     // Message nested in array literal with trailing array items
217     (@array $msg:ident $repeated:ident [] $($msgtype:ident)::+ { $($value:tt)* }, $($rest:tt)*) => {
218         proto_internal!(@array $msg $repeated [
219                 {
220                     let mut $msg = $($msgtype)::+::new();
221                     proto_internal!(@merge $msg $($value)*);
222                     proto_internal!(@msg $msg $($value)*);
223                     $msg
224                 }
225             ] $($rest)*)
226     };
227     // with leading ::
228     (@array $msg:ident $repeated:ident [] ::$($msgtype:ident)::+ { $($value:tt)* }, $($rest:tt)*) => {
229         proto_internal!(@array $msg $repeated [
230                 {
231                     let mut $msg = ::$($msgtype)::+::new();
232                     proto_internal!(@merge $msg $($value)*);
233                     proto_internal!(@msg $msg $($value)*);
234                     $msg
235                 }
236             ] $($rest)*)
237     };
238     // Message nested in [] literal
239     (@array $msg:ident $repeated:ident [] $($msgtype:ident)::+ { $($value:tt)* }) => {
240         [
241             {
242                 let mut $msg = $($msgtype)::+::new();
243                 proto_internal!(@merge $msg $($value)*);
244                 proto_internal!(@msg $msg $($value)*);
245                 $msg
246             }
247         ]
248     };
249     (@array $msg:ident $repeated:ident [] ::$($msgtype:ident)::+ { $($value:tt)* }) => {
250         [
251             {
252                 let mut $msg = ::$($msgtype)::+::new();
253                 proto_internal!(@merge $msg $($value)*);
254                 proto_internal!(@msg $msg $($value)*);
255                 $msg
256             }
257         ]
258     };
259 
260     (@array $msg:ident $repeated:ident [$($vals:expr),+] $expr:expr, $($rest:tt)*) => {
261         proto_internal!(@array $msg $repeated [$($vals),+, $expr]  $($rest)*)
262     };
263     (@array $msg:ident $repeated:ident [$($vals:expr),+] $expr:expr) => {
264         [$($vals),+, $expr]
265     };
266     (@array $msg:ident $repeated:ident [] $expr:expr, $($rest:tt)*) => {
267         proto_internal!(@array $msg $repeated [$expr]  $($rest)*)
268     };
269     (@array $msg:ident $repeated:ident [] $expr:expr) => {
270         [$expr]
271     };
272     (@array $msg:ident $repeated:ident []) => {
273         []
274     };
275 
276     // field: expr,
277     (@msg $msg:ident $ident:ident : $expr:expr, $($rest:tt)*) => {
278         // delegate without ,
279         proto_internal!(@msg $msg $ident : $expr);
280         proto_internal!(@msg $msg $($rest)*);
281     };
282 
283     // field: expr
284     (@msg $msg:ident $ident:ident : $expr:expr) => {
285         $crate::__internal::paste!($msg.[<set_ $ident>]($expr));
286     };
287 
288     (@msg $msg:ident ..$expr:expr) => {
289     };
290 
291     (@msg $msg:ident) => {};
292     (@merge $msg:ident) => {};
293 
294     // entry point
295     ($msgtype:ty { $($tt:tt)* }) => {
296         {
297             let mut message = <$msgtype>::new();
298             proto_internal!(@merge message $($tt)*);
299             proto_internal!(@msg message $($tt)*);
300             message
301         }
302     };
303 }
304