prost_derive/field/
message.rs
1use anyhow::{bail, Error};
2use proc_macro2::TokenStream;
3use quote::{quote, ToTokens};
4use syn::Meta;
5
6use crate::field::{set_bool, set_option, tag_attr, word_attr, Label};
7
8#[derive(Clone)]
9pub struct Field {
10 pub label: Label,
11 pub tag: u32,
12}
13
14impl Field {
15 pub fn new(attrs: &[Meta], inferred_tag: Option<u32>) -> Result<Option<Field>, Error> {
16 let mut message = false;
17 let mut label = None;
18 let mut tag = None;
19 let mut boxed = false;
20
21 let mut unknown_attrs = Vec::new();
22
23 for attr in attrs {
24 if word_attr("message", attr) {
25 set_bool(&mut message, "duplicate message attribute")?;
26 } else if word_attr("boxed", attr) {
27 set_bool(&mut boxed, "duplicate boxed attribute")?;
28 } else if let Some(t) = tag_attr(attr)? {
29 set_option(&mut tag, t, "duplicate tag attributes")?;
30 } else if let Some(l) = Label::from_attr(attr) {
31 set_option(&mut label, l, "duplicate label attributes")?;
32 } else {
33 unknown_attrs.push(attr);
34 }
35 }
36
37 if !message {
38 return Ok(None);
39 }
40
41 if !unknown_attrs.is_empty() {
42 bail!(
43 "unknown attribute(s) for message field: #[prost({})]",
44 quote!(#(#unknown_attrs),*)
45 );
46 }
47
48 let tag = match tag.or(inferred_tag) {
49 Some(tag) => tag,
50 None => bail!("message field is missing a tag attribute"),
51 };
52
53 Ok(Some(Field {
54 label: label.unwrap_or(Label::Optional),
55 tag,
56 }))
57 }
58
59 pub fn new_oneof(attrs: &[Meta]) -> Result<Option<Field>, Error> {
60 if let Some(mut field) = Field::new(attrs, None)? {
61 if let Some(attr) = attrs.iter().find(|attr| Label::from_attr(attr).is_some()) {
62 bail!(
63 "invalid attribute for oneof field: {}",
64 attr.path().into_token_stream()
65 );
66 }
67 field.label = Label::Required;
68 Ok(Some(field))
69 } else {
70 Ok(None)
71 }
72 }
73
74 pub fn encode(&self, ident: TokenStream) -> TokenStream {
75 let tag = self.tag;
76 match self.label {
77 Label::Optional => quote! {
78 if let Some(ref msg) = #ident {
79 ::prost::encoding::message::encode(#tag, msg, buf);
80 }
81 },
82 Label::Required => quote! {
83 ::prost::encoding::message::encode(#tag, &#ident, buf);
84 },
85 Label::Repeated => quote! {
86 for msg in &#ident {
87 ::prost::encoding::message::encode(#tag, msg, buf);
88 }
89 },
90 }
91 }
92
93 pub fn merge(&self, ident: TokenStream) -> TokenStream {
94 match self.label {
95 Label::Optional => quote! {
96 ::prost::encoding::message::merge(wire_type,
97 #ident.get_or_insert_with(::core::default::Default::default),
98 buf,
99 ctx)
100 },
101 Label::Required => quote! {
102 ::prost::encoding::message::merge(wire_type, #ident, buf, ctx)
103 },
104 Label::Repeated => quote! {
105 ::prost::encoding::message::merge_repeated(wire_type, #ident, buf, ctx)
106 },
107 }
108 }
109
110 pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
111 let tag = self.tag;
112 match self.label {
113 Label::Optional => quote! {
114 #ident.as_ref().map_or(0, |msg| ::prost::encoding::message::encoded_len(#tag, msg))
115 },
116 Label::Required => quote! {
117 ::prost::encoding::message::encoded_len(#tag, &#ident)
118 },
119 Label::Repeated => quote! {
120 ::prost::encoding::message::encoded_len_repeated(#tag, &#ident)
121 },
122 }
123 }
124
125 pub fn clear(&self, ident: TokenStream) -> TokenStream {
126 match self.label {
127 Label::Optional => quote!(#ident = ::core::option::Option::None),
128 Label::Required => quote!(#ident.clear()),
129 Label::Repeated => quote!(#ident.clear()),
130 }
131 }
132}