| // Protocol Buffers - Google's data interchange format |
| // Copyright 2024 Google LLC. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file or at |
| // https://developers.google.com/open-source/licenses/bsd |
| |
| /// proto! enables the use of Rust struct initialization syntax to create |
| /// protobuf messages. The macro does its best to try and detect the |
| /// initialization of submessages, but it is only able to do so while the |
| /// submessage is being defined as part of the original struct literal. |
| /// Introducing an expression using () or {} as the value of a field will |
| /// require another call to this macro in order to return a submessage |
| /// literal.``` /* |
| /// Given the following proto definition |
| /// message Data { |
| /// int32 number = 1; |
| /// string letters = 2; |
| /// Data nested = 3; |
| /// } |
| /// */ |
| /// use protobuf::proto; |
| /// let message = proto!(Data { |
| /// number: 42, |
| /// letters: "Hello World", |
| /// nested: Data { |
| /// number: { |
| /// let x = 100; |
| /// x + 1 |
| /// } |
| /// } |
| /// }); ``` |
| #[macro_export] |
| macro_rules! proto { |
| ($msgtype:ty { $($tt:tt)* }) => { |
| $crate::proto_internal!($msgtype { $($tt)* }) |
| } |
| } |
| |
| #[macro_export(local_inner_macros)] |
| #[doc(hidden)] |
| macro_rules! proto_internal { |
| (@merge $msg:ident $ident:ident : $expr:expr, $($rest:tt)*) => { |
| proto_internal!(@merge $msg $($rest)*); |
| }; |
| |
| (@merge $msg:ident $ident:ident : $expr:expr) => { |
| }; |
| |
| (@merge $msg:ident ..$expr:expr) => { |
| $msg.merge_from($expr); |
| }; |
| |
| // nested message, |
| (@msg $msg:ident $submsg:ident : $($msgtype:ident)::+ { $field:ident : $($value:tt)* }, $($rest:tt)*) => { |
| proto_internal!(@msg $msg $submsg : $($msgtype)::+ { $field : $($value)* }); |
| proto_internal!(@msg $msg $($rest)*); |
| }; |
| (@msg $msg:ident $submsg:ident : ::$($msgtype:ident)::+ { $field:ident : $($value:tt)* }, $($rest:tt)*) => { |
| proto_internal!(@msg $msg $submsg : ::$($msgtype)::+ { $field : $($value)* }); |
| proto_internal!(@msg $msg $($rest)*); |
| }; |
| |
| // nested message |
| (@msg $msg:ident $submsg:ident : $($msgtype:ident)::+ { $field:ident : $($value:tt)* }) => { |
| { |
| let mut $msg: <$($msgtype)::+ as $crate::MutProxied>::Mut<'_> = $crate::__internal::paste!($msg.[<$submsg _mut>]()); |
| proto_internal!(@merge $msg $field : $($value)*); |
| proto_internal!(@msg $msg $field : $($value)*); |
| } |
| }; |
| (@msg $msg:ident $submsg:ident : ::$($msgtype:ident)::+ { $field:ident : $($value:tt)* }) => { |
| { |
| let mut $msg: <::$($msgtype)::+ as $crate::MutProxied>::Mut<'_> = $crate::__internal::paste!($msg.[<$submsg _mut>]()); |
| proto_internal!(@merge $msg $field : $($value)*); |
| proto_internal!(@msg $msg $field : $($value)*); |
| } |
| }; |
| |
| // empty nested message, |
| (@msg $msg:ident $submsg:ident : $($msgtype:ident)::+ { }, $($rest:tt)*) => { |
| proto_internal!(@msg $msg $submsg : $($msgtype)::+ { }); |
| proto_internal!(@msg $msg $($rest)*); |
| }; |
| (@msg $msg:ident $submsg:ident : ::$($msgtype:ident)::+ { }, $($rest:tt)*) => { |
| proto_internal!(@msg $msg $submsg : ::$($msgtype)::+ { }); |
| proto_internal!(@msg $msg $($rest)*); |
| }; |
| |
| // empty nested message |
| (@msg $msg:ident $submsg:ident : $($msgtype:ident)::+ { }) => { |
| { |
| let mut $msg: <$($msgtype)::+ as $crate::MutProxied>::Mut<'_> = $crate::__internal::paste!($msg.[<$submsg _mut>]()); |
| } |
| }; |
| (@msg $msg:ident $submsg:ident : ::$($msgtype:ident)::+ { }) => { |
| { |
| let mut $msg: <::$($msgtype)::+ as $crate::MutProxied>::Mut<'_> = $crate::__internal::paste!($msg.[<$submsg _mut>]()); |
| } |
| }; |
| |
| // field: expr, |
| (@msg $msg:ident $ident:ident : $expr:expr, $($rest:tt)*) => { |
| // delegate without , |
| proto_internal!(@msg $msg $ident : $expr); |
| proto_internal!(@msg $msg $($rest)*); |
| }; |
| |
| // field: expr |
| (@msg $msg:ident $ident:ident : $expr:expr) => { |
| $crate::__internal::paste!($msg.[<set_ $ident>]($expr)); |
| }; |
| |
| (@msg $msg:ident ..$expr:expr) => { |
| }; |
| |
| (@msg $msg:ident) => {}; |
| (@merge $msg:ident) => {}; |
| |
| // entry point |
| ($msgtype:ty { $($tt:tt)* }) => { |
| { |
| let mut message = <$msgtype>::new(); |
| proto_internal!(@merge message $($tt)*); |
| proto_internal!(@msg message $($tt)*); |
| message |
| } |
| }; |
| } |