prost_derive/field/
oneof.rs
1use 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 if !unknown_attrs.is_empty() {
48 bail!(
49 "unknown attribute(s) for message field: #[prost({})]",
50 quote!(#(#unknown_attrs),*)
51 );
52 }
53
54 let tags = match tags {
55 Some(tags) => tags,
56 None => bail!("oneof field is missing a tags attribute"),
57 };
58
59 Ok(Some(Field { ty, tags }))
60 }
61
62 pub fn encode(&self, ident: TokenStream) -> TokenStream {
64 quote! {
65 if let Some(ref oneof) = #ident {
66 oneof.encode(buf)
67 }
68 }
69 }
70
71 pub fn merge(&self, ident: TokenStream) -> TokenStream {
73 let ty = &self.ty;
74 quote! {
75 #ty::merge(#ident, tag, wire_type, buf, ctx)
76 }
77 }
78
79 pub fn encoded_len(&self, ident: TokenStream) -> TokenStream {
81 let ty = &self.ty;
82 quote! {
83 #ident.as_ref().map_or(0, #ty::encoded_len)
84 }
85 }
86
87 pub fn clear(&self, ident: TokenStream) -> TokenStream {
88 quote!(#ident = ::core::option::Option::None)
89 }
90}