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