prost_derive/field/
oneof.rs1use anyhow::{bail, Error};
2use proc_macro2::TokenStream;
3use quote::quote;
4use syn::{parse_str, Expr, ExprLit, Ident, Lit, Meta, MetaNameValue, 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 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 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 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 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
89 pub fn clear(&self, ident: TokenStream) -> TokenStream {
90 quote!(#ident = ::core::option::Option::None)
91 }
92}