1 use anyhow::{bail, Error};
2 use proc_macro2::TokenStream;
3 use quote::quote;
4 use syn::{parse_str, Expr, ExprLit, Ident, Lit, Meta, MetaNameValue, Path};
5 
6 use crate::field::{set_option, tags_attr};
7 
8 #[derive(Clone)]
9 pub struct Field {
10     pub ty: Path,
11     pub tags: Vec<u32>,
12 }
13 
14 impl Field {
new(attrs: &[Meta]) -> Result<Option<Field>, Error>15     pub fn new(attrs: &[Meta]) -> Result<Option<Field>, Error> {
16         let mut ty = None;
17         let mut tags = None;
18         let mut unknown_attrs = Vec::new();
19 
20         for attr in attrs {
21             if attr.path().is_ident("oneof") {
22                 let t = match *attr {
23                     Meta::NameValue(MetaNameValue {
24                         value:
25                             Expr::Lit(ExprLit {
26                                 lit: Lit::Str(ref lit),
27                                 ..
28                             }),
29                         ..
30                     }) => parse_str::<Path>(&lit.value())?,
31                     Meta::List(ref list) => list.parse_args::<Ident>()?.into(),
32                     _ => bail!("invalid oneof attribute: {:?}", attr),
33                 };
34                 set_option(&mut ty, t, "duplicate oneof attribute")?;
35             } else if let Some(t) = tags_attr(attr)? {
36                 set_option(&mut tags, t, "duplicate tags attributes")?;
37             } else {
38                 unknown_attrs.push(attr);
39             }
40         }
41 
42         let ty = match ty {
43             Some(ty) => ty,
44             None => return Ok(None),
45         };
46 
47         match unknown_attrs.len() {
48             0 => (),
49             1 => bail!(
50                 "unknown attribute for message field: {:?}",
51                 unknown_attrs[0]
52             ),
53             _ => bail!("unknown attributes for message field: {:?}", unknown_attrs),
54         }
55 
56         let tags = match tags {
57             Some(tags) => tags,
58             None => bail!("oneof field is missing a tags attribute"),
59         };
60 
61         Ok(Some(Field { ty, tags }))
62     }
63 
64     /// Returns a statement which encodes the oneof field.
encode(&self, ident: TokenStream) -> TokenStream65     pub fn encode(&self, ident: TokenStream) -> TokenStream {
66         quote! {
67             if let Some(ref oneof) = #ident {
68                 oneof.encode(buf)
69             }
70         }
71     }
72 
73     /// Returns an expression which evaluates to the result of decoding the oneof field.
merge(&self, ident: TokenStream) -> TokenStream74     pub fn merge(&self, ident: TokenStream) -> TokenStream {
75         let ty = &self.ty;
76         quote! {
77             #ty::merge(#ident, tag, wire_type, buf, ctx)
78         }
79     }
80 
81     /// Returns an expression which evaluates to the encoded length of the oneof field.
encoded_len(&self, ident: TokenStream) -> TokenStream82     pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
83         let ty = &self.ty;
84         quote! {
85             #ident.as_ref().map_or(0, #ty::encoded_len)
86         }
87     }
88 
clear(&self, ident: TokenStream) -> TokenStream89     pub fn clear(&self, ident: TokenStream) -> TokenStream {
90         quote!(#ident = ::core::option::Option::None)
91     }
92 }
93