prost_derive/field/
oneof.rs1use anyhow::{bail, Error};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{parse_str, Lit, Meta, MetaNameValue, NestedMeta, Path};
5
6use crate::field::{set_option, tags_attr};
7
8#[derive(Clone)]
9pub struct Field {
10 pub ty: Path,
11 pub tags: Vec<u32>,
12}
13
14impl Field {
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 lit: Lit::Str(ref lit),
25 ..
26 }) => parse_str::<Path>(&lit.value())?,
27 Meta::List(ref list) if list.nested.len() == 1 => {
28 if let NestedMeta::Meta(Meta::Path(ref path)) = list.nested[0] {
30 if let Some(ident) = path.get_ident() {
31 Path::from(ident.clone())
32 } else {
33 bail!("invalid oneof attribute: item must be an identifier");
34 }
35 } else {
36 bail!("invalid oneof attribute: item must be an identifier");
37 }
38 }
39 _ => bail!("invalid oneof attribute: {:?}", attr),
40 };
41 set_option(&mut ty, t, "duplicate oneof attribute")?;
42 } else if let Some(t) = tags_attr(attr)? {
43 set_option(&mut tags, t, "duplicate tags attributes")?;
44 } else {
45 unknown_attrs.push(attr);
46 }
47 }
48
49 let ty = match ty {
50 Some(ty) => ty,
51 None => return Ok(None),
52 };
53
54 match unknown_attrs.len() {
55 0 => (),
56 1 => bail!(
57 "unknown attribute for message field: {:?}",
58 unknown_attrs[0]
59 ),
60 _ => bail!("unknown attributes for message field: {:?}", unknown_attrs),
61 }
62
63 let tags = match tags {
64 Some(tags) => tags,
65 None => bail!("oneof field is missing a tags attribute"),
66 };
67
68 Ok(Some(Field { ty, tags }))
69 }
70
71 pub fn encode(&self, ident: TokenStream) -> TokenStream {
73 quote! {
74 if let Some(ref oneof) = #ident {
75 oneof.encode(buf)
76 }
77 }
78 }
79
80 pub fn merge(&self, ident: TokenStream) -> TokenStream {
82 let ty = &self.ty;
83 quote! {
84 #ty::merge(#ident, tag, wire_type, buf, ctx)
85 }
86 }
87
88 pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
90 let ty = &self.ty;
91 quote! {
92 #ident.as_ref().map_or(0, #ty::encoded_len)
93 }
94 }
95
96 pub fn clear(&self, ident: TokenStream) -> TokenStream {
97 quote!(#ident = ::core::option::Option::None)
98 }
99}