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