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