prost_derive/field/
message.rs1use 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 match unknown_attrs.len() {
42 0 => (),
43 1 => bail!(
44 "unknown attribute for message field: {:?}",
45 unknown_attrs[0]
46 ),
47 _ => bail!("unknown attributes for message field: {:?}", unknown_attrs),
48 }
49
50 let tag = match tag.or(inferred_tag) {
51 Some(tag) => tag,
52 None => bail!("message field is missing a tag attribute"),
53 };
54
55 Ok(Some(Field {
56 label: label.unwrap_or(Label::Optional),
57 tag,
58 }))
59 }
60
61 pub fn new_oneof(attrs: &[Meta]) -> Result<Option<Field>, Error> {
62 if let Some(mut field) = Field::new(attrs, None)? {
63 if let Some(attr) = attrs.iter().find(|attr| Label::from_attr(attr).is_some()) {
64 bail!(
65 "invalid attribute for oneof field: {}",
66 attr.path().into_token_stream()
67 );
68 }
69 field.label = Label::Required;
70 Ok(Some(field))
71 } else {
72 Ok(None)
73 }
74 }
75
76 pub fn encode(&self, ident: TokenStream) -> TokenStream {
77 let tag = self.tag;
78 match self.label {
79 Label::Optional => quote! {
80 if let Some(ref msg) = #ident {
81 ::prost::encoding::message::encode(#tag, msg, buf);
82 }
83 },
84 Label::Required => quote! {
85 ::prost::encoding::message::encode(#tag, &#ident, buf);
86 },
87 Label::Repeated => quote! {
88 for msg in &#ident {
89 ::prost::encoding::message::encode(#tag, msg, buf);
90 }
91 },
92 }
93 }
94
95 pub fn merge(&self, ident: TokenStream) -> TokenStream {
96 match self.label {
97 Label::Optional => quote! {
98 ::prost::encoding::message::merge(wire_type,
99 #ident.get_or_insert_with(::core::default::Default::default),
100 buf,
101 ctx)
102 },
103 Label::Required => quote! {
104 ::prost::encoding::message::merge(wire_type, #ident, buf, ctx)
105 },
106 Label::Repeated => quote! {
107 ::prost::encoding::message::merge_repeated(wire_type, #ident, buf, ctx)
108 },
109 }
110 }
111
112 pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
113 let tag = self.tag;
114 match self.label {
115 Label::Optional => quote! {
116 #ident.as_ref().map_or(0, |msg| ::prost::encoding::message::encoded_len(#tag, msg))
117 },
118 Label::Required => quote! {
119 ::prost::encoding::message::encoded_len(#tag, &#ident)
120 },
121 Label::Repeated => quote! {
122 ::prost::encoding::message::encoded_len_repeated(#tag, &#ident)
123 },
124 }
125 }
126
127 pub fn clear(&self, ident: TokenStream) -> TokenStream {
128 match self.label {
129 Label::Optional => quote!(#ident = ::core::option::Option::None),
130 Label::Required => quote!(#ident.clear()),
131 Label::Repeated => quote!(#ident.clear()),
132 }
133 }
134}