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