1 use anyhow::{bail, Error};
2 use proc_macro2::TokenStream;
3 use quote::{quote, ToTokens};
4 use syn::Meta;
5 
6 use crate::field::{set_bool, set_option, tag_attr, word_attr, Label};
7 
8 #[derive(Clone)]
9 pub struct Field {
10     pub label: Label,
11     pub tag: u32,
12 }
13 
14 impl Field {
new(attrs: &[Meta], inferred_tag: Option<u32>) -> Result<Option<Field>, Error>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 
new_oneof(attrs: &[Meta]) -> Result<Option<Field>, Error>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 
encode(&self, ident: TokenStream) -> TokenStream76     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 
merge(&self, ident: TokenStream) -> TokenStream95     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 
encoded_len(&self, ident: TokenStream) -> TokenStream112     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 
clear(&self, ident: TokenStream) -> TokenStream127     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 }
135