prost_derive/field/
mod.rs

1mod group;
2mod map;
3mod message;
4mod oneof;
5mod scalar;
6
7use std::fmt;
8use std::slice;
9
10use anyhow::{bail, Error};
11use proc_macro2::TokenStream;
12use quote::quote;
13use syn::punctuated::Punctuated;
14use syn::{Attribute, Expr, ExprLit, Lit, LitBool, LitInt, Meta, MetaNameValue, Token};
15
16#[derive(Clone)]
17pub enum Field {
18    /// A scalar field.
19    Scalar(scalar::Field),
20    /// A message field.
21    Message(message::Field),
22    /// A map field.
23    Map(map::Field),
24    /// A oneof field.
25    Oneof(oneof::Field),
26    /// A group field.
27    Group(group::Field),
28}
29
30impl Field {
31    /// Creates a new `Field` from an iterator of field attributes.
32    ///
33    /// If the meta items are invalid, an error will be returned.
34    /// If the field should be ignored, `None` is returned.
35    pub fn new(attrs: Vec<Attribute>, inferred_tag: Option<u32>) -> Result<Option<Field>, Error> {
36        let attrs = prost_attrs(attrs)?;
37
38        // TODO: check for ignore attribute.
39
40        let field = if let Some(field) = scalar::Field::new(&attrs, inferred_tag)? {
41            Field::Scalar(field)
42        } else if let Some(field) = message::Field::new(&attrs, inferred_tag)? {
43            Field::Message(field)
44        } else if let Some(field) = map::Field::new(&attrs, inferred_tag)? {
45            Field::Map(field)
46        } else if let Some(field) = oneof::Field::new(&attrs)? {
47            Field::Oneof(field)
48        } else if let Some(field) = group::Field::new(&attrs, inferred_tag)? {
49            Field::Group(field)
50        } else {
51            bail!("no type attribute");
52        };
53
54        Ok(Some(field))
55    }
56
57    /// Creates a new oneof `Field` from an iterator of field attributes.
58    ///
59    /// If the meta items are invalid, an error will be returned.
60    /// If the field should be ignored, `None` is returned.
61    pub fn new_oneof(attrs: Vec<Attribute>) -> Result<Option<Field>, Error> {
62        let attrs = prost_attrs(attrs)?;
63
64        // TODO: check for ignore attribute.
65
66        let field = if let Some(field) = scalar::Field::new_oneof(&attrs)? {
67            Field::Scalar(field)
68        } else if let Some(field) = message::Field::new_oneof(&attrs)? {
69            Field::Message(field)
70        } else if let Some(field) = map::Field::new_oneof(&attrs)? {
71            Field::Map(field)
72        } else if let Some(field) = group::Field::new_oneof(&attrs)? {
73            Field::Group(field)
74        } else {
75            bail!("no type attribute for oneof field");
76        };
77
78        Ok(Some(field))
79    }
80
81    pub fn tags(&self) -> Vec<u32> {
82        match *self {
83            Field::Scalar(ref scalar) => vec![scalar.tag],
84            Field::Message(ref message) => vec![message.tag],
85            Field::Map(ref map) => vec![map.tag],
86            Field::Oneof(ref oneof) => oneof.tags.clone(),
87            Field::Group(ref group) => vec![group.tag],
88        }
89    }
90
91    /// Returns a statement which encodes the field.
92    pub fn encode(&self, ident: TokenStream) -> TokenStream {
93        match *self {
94            Field::Scalar(ref scalar) => scalar.encode(ident),
95            Field::Message(ref message) => message.encode(ident),
96            Field::Map(ref map) => map.encode(ident),
97            Field::Oneof(ref oneof) => oneof.encode(ident),
98            Field::Group(ref group) => group.encode(ident),
99        }
100    }
101
102    /// Returns an expression which evaluates to the result of merging a decoded
103    /// value into the field.
104    pub fn merge(&self, ident: TokenStream) -> TokenStream {
105        match *self {
106            Field::Scalar(ref scalar) => scalar.merge(ident),
107            Field::Message(ref message) => message.merge(ident),
108            Field::Map(ref map) => map.merge(ident),
109            Field::Oneof(ref oneof) => oneof.merge(ident),
110            Field::Group(ref group) => group.merge(ident),
111        }
112    }
113
114    /// Returns an expression which evaluates to the encoded length of the field.
115    pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
116        match *self {
117            Field::Scalar(ref scalar) => scalar.encoded_len(ident),
118            Field::Map(ref map) => map.encoded_len(ident),
119            Field::Message(ref msg) => msg.encoded_len(ident),
120            Field::Oneof(ref oneof) => oneof.encoded_len(ident),
121            Field::Group(ref group) => group.encoded_len(ident),
122        }
123    }
124
125    /// Returns a statement which clears the field.
126    pub fn clear(&self, ident: TokenStream) -> TokenStream {
127        match *self {
128            Field::Scalar(ref scalar) => scalar.clear(ident),
129            Field::Message(ref message) => message.clear(ident),
130            Field::Map(ref map) => map.clear(ident),
131            Field::Oneof(ref oneof) => oneof.clear(ident),
132            Field::Group(ref group) => group.clear(ident),
133        }
134    }
135
136    pub fn default(&self) -> TokenStream {
137        match *self {
138            Field::Scalar(ref scalar) => scalar.default(),
139            _ => quote!(::core::default::Default::default()),
140        }
141    }
142
143    /// Produces the fragment implementing debug for the given field.
144    pub fn debug(&self, ident: TokenStream) -> TokenStream {
145        match *self {
146            Field::Scalar(ref scalar) => {
147                let wrapper = scalar.debug(quote!(ScalarWrapper));
148                quote! {
149                    {
150                        #wrapper
151                        ScalarWrapper(&#ident)
152                    }
153                }
154            }
155            Field::Map(ref map) => {
156                let wrapper = map.debug(quote!(MapWrapper));
157                quote! {
158                    {
159                        #wrapper
160                        MapWrapper(&#ident)
161                    }
162                }
163            }
164            _ => quote!(&#ident),
165        }
166    }
167
168    pub fn methods(&self, ident: &TokenStream) -> Option<TokenStream> {
169        match *self {
170            Field::Scalar(ref scalar) => scalar.methods(ident),
171            Field::Map(ref map) => map.methods(ident),
172            _ => None,
173        }
174    }
175}
176
177#[derive(Clone, Copy, PartialEq, Eq)]
178pub enum Label {
179    /// An optional field.
180    Optional,
181    /// A required field.
182    Required,
183    /// A repeated field.
184    Repeated,
185}
186
187impl Label {
188    fn as_str(self) -> &'static str {
189        match self {
190            Label::Optional => "optional",
191            Label::Required => "required",
192            Label::Repeated => "repeated",
193        }
194    }
195
196    fn variants() -> slice::Iter<'static, Label> {
197        const VARIANTS: &[Label] = &[Label::Optional, Label::Required, Label::Repeated];
198        VARIANTS.iter()
199    }
200
201    /// Parses a string into a field label.
202    /// If the string doesn't match a field label, `None` is returned.
203    fn from_attr(attr: &Meta) -> Option<Label> {
204        if let Meta::Path(ref path) = *attr {
205            for &label in Label::variants() {
206                if path.is_ident(label.as_str()) {
207                    return Some(label);
208                }
209            }
210        }
211        None
212    }
213}
214
215impl fmt::Debug for Label {
216    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
217        f.write_str(self.as_str())
218    }
219}
220
221impl fmt::Display for Label {
222    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
223        f.write_str(self.as_str())
224    }
225}
226
227/// Get the items belonging to the 'prost' list attribute, e.g. `#[prost(foo, bar="baz")]`.
228fn prost_attrs(attrs: Vec<Attribute>) -> Result<Vec<Meta>, Error> {
229    let mut result = Vec::new();
230    for attr in attrs.iter() {
231        if let Meta::List(meta_list) = &attr.meta {
232            if meta_list.path.is_ident("prost") {
233                result.extend(
234                    meta_list
235                        .parse_args_with(Punctuated::<Meta, Token![,]>::parse_terminated)?
236                        .into_iter(),
237                )
238            }
239        }
240    }
241    Ok(result)
242}
243
244pub fn set_option<T>(option: &mut Option<T>, value: T, message: &str) -> Result<(), Error>
245where
246    T: fmt::Debug,
247{
248    if let Some(ref existing) = *option {
249        bail!("{}: {:?} and {:?}", message, existing, value);
250    }
251    *option = Some(value);
252    Ok(())
253}
254
255pub fn set_bool(b: &mut bool, message: &str) -> Result<(), Error> {
256    if *b {
257        bail!("{}", message);
258    } else {
259        *b = true;
260        Ok(())
261    }
262}
263
264/// Unpacks an attribute into a (key, boolean) pair, returning the boolean value.
265/// If the key doesn't match the attribute, `None` is returned.
266fn bool_attr(key: &str, attr: &Meta) -> Result<Option<bool>, Error> {
267    if !attr.path().is_ident(key) {
268        return Ok(None);
269    }
270    match *attr {
271        Meta::Path(..) => Ok(Some(true)),
272        Meta::List(ref meta_list) => Ok(Some(meta_list.parse_args::<LitBool>()?.value())),
273        Meta::NameValue(MetaNameValue {
274            value:
275                Expr::Lit(ExprLit {
276                    lit: Lit::Str(ref lit),
277                    ..
278                }),
279            ..
280        }) => lit
281            .value()
282            .parse::<bool>()
283            .map_err(Error::from)
284            .map(Option::Some),
285        Meta::NameValue(MetaNameValue {
286            value:
287                Expr::Lit(ExprLit {
288                    lit: Lit::Bool(LitBool { value, .. }),
289                    ..
290                }),
291            ..
292        }) => Ok(Some(value)),
293        _ => bail!("invalid {} attribute", key),
294    }
295}
296
297/// Checks if an attribute matches a word.
298fn word_attr(key: &str, attr: &Meta) -> bool {
299    if let Meta::Path(ref path) = *attr {
300        path.is_ident(key)
301    } else {
302        false
303    }
304}
305
306pub(super) fn tag_attr(attr: &Meta) -> Result<Option<u32>, Error> {
307    if !attr.path().is_ident("tag") {
308        return Ok(None);
309    }
310    match *attr {
311        Meta::List(ref meta_list) => Ok(Some(meta_list.parse_args::<LitInt>()?.base10_parse()?)),
312        Meta::NameValue(MetaNameValue {
313            value: Expr::Lit(ref expr),
314            ..
315        }) => match expr.lit {
316            Lit::Str(ref lit) => lit
317                .value()
318                .parse::<u32>()
319                .map_err(Error::from)
320                .map(Option::Some),
321            Lit::Int(ref lit) => Ok(Some(lit.base10_parse()?)),
322            _ => bail!("invalid tag attribute: {:?}", attr),
323        },
324        _ => bail!("invalid tag attribute: {:?}", attr),
325    }
326}
327
328fn tags_attr(attr: &Meta) -> Result<Option<Vec<u32>>, Error> {
329    if !attr.path().is_ident("tags") {
330        return Ok(None);
331    }
332    match *attr {
333        Meta::List(ref meta_list) => Ok(Some(
334            meta_list
335                .parse_args_with(Punctuated::<LitInt, Token![,]>::parse_terminated)?
336                .iter()
337                .map(LitInt::base10_parse)
338                .collect::<Result<Vec<_>, _>>()?,
339        )),
340        Meta::NameValue(MetaNameValue {
341            value:
342                Expr::Lit(ExprLit {
343                    lit: Lit::Str(ref lit),
344                    ..
345                }),
346            ..
347        }) => lit
348            .value()
349            .split(',')
350            .map(|s| s.trim().parse::<u32>().map_err(Error::from))
351            .collect::<Result<Vec<u32>, _>>()
352            .map(Some),
353        _ => bail!("invalid tag attribute: {:?}", attr),
354    }
355}