use anyhow::{bail, Error}; use itertools::Itertools; use proc_macro::TokenStream; use proc_macro2::Span; use quote::quote; use syn::{
punctuated::Punctuated, Data, DataEnum, DataStruct, DeriveInput, Expr, Fields, FieldsNamed,
FieldsUnnamed, Ident, Index, Variant,
};
let variant_data = match input.data {
Data::Struct(variant_data) => variant_data,
Data::Enum(..) => bail!("Message can not be derived for an enum"),
Data::Union(..) => bail!("Message can not be derived for a union"),
};
let generics = &input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
letmut next_tag: u32 = 1; letmut fields = fields
.into_iter()
.enumerate()
.flat_map(|(i, field)| { let field_ident = field.ident.map(|x| quote!(#x)).unwrap_or_else(|| { let index = Index {
index: i as u32,
span: Span::call_site(),
};
quote!(#index)
}); match Field::new(field.attrs, Some(next_tag)) {
Ok(Some(field)) => {
next_tag = field.tags().iter().max().map(|t| t + 1).unwrap_or(next_tag);
Some(Ok((field_ident, field)))
}
Ok(None) => None,
Err(err) => Some(Err(
err.context(format!("invalid message field {}.{}", ident, field_ident))
)),
}
})
.collect::<Result<Vec<_>, _>>()?;
// We want Debug to be in declaration order let unsorted_fields = fields.clone();
// Sort the fields by tag number so that fields will be encoded in tag order. // TODO: This encodes oneof fields in the position of their lowest tag, // regardless of the currently occupied variant, is that consequential? // See: https://developers.google.com/protocol-buffers/docs/encoding#order
fields.sort_by_key(|&(_, ref field)| field.tags().into_iter().min().unwrap()); let fields = fields;
letmut tags = fields
.iter()
.flat_map(|&(_, ref field)| field.tags())
.collect::<Vec<_>>(); let num_tags = tags.len();
tags.sort_unstable();
tags.dedup(); if tags.len() != num_tags {
bail!("message {} has fields with duplicate tags", ident);
}
let encoded_len = fields
.iter()
.map(|&(ref field_ident, ref field)| field.encoded_len(quote!(self.#field_ident)));
let encode = fields
.iter()
.map(|&(ref field_ident, ref field)| field.encode(quote!(self.#field_ident)));
let merge = fields.iter().map(|&(ref field_ident, ref field)| { let merge = field.merge(quote!(value)); let tags = field.tags().into_iter().map(|tag| quote!(#tag)); let tags = Itertools::intersperse(tags, quote!(|));
fn try_enumeration(input: TokenStream) -> Result<TokenStream, Error> { let input: DeriveInput = syn::parse(input)?; let ident = input.ident;
let generics = &input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
let punctuated_variants = match input.data {
Data::Enum(DataEnum { variants, .. }) => variants,
Data::Struct(_) => bail!("Enumeration can not be derived for a struct"),
Data::Union(..) => bail!("Enumeration can not be derived for a union"),
};
// Map the variants into 'fields'. letmut variants: Vec<(Ident, Expr)> = Vec::new(); for Variant {
ident,
fields,
discriminant,
..
} in punctuated_variants
{ match fields {
Fields::Unit => (),
Fields::Named(_) | Fields::Unnamed(_) => {
bail!("Enumeration variants may not have fields")
}
}
match discriminant {
Some((_, expr)) => variants.push((ident, expr)),
None => bail!("Enumeration variants must have a discriminant"),
}
}
if variants.is_empty() {
panic!("Enumeration must have at least one variant");
}
let default = variants[0].0.clone();
let is_valid = variants
.iter()
.map(|&(_, ref value)| quote!(#value => true)); let from = variants.iter().map(
|&(ref variant, ref value)| quote!(#value => ::core::option::Option::Some(#ident::#variant)),
);
let is_valid_doc = format!("Returns `true` if `value` is a variant of `{}`.", ident); let from_i32_doc = format!( "Converts an `i32` to a `{}`, or `None` if `value` is not a valid variant.",
ident
);
let expanded = quote! { impl#impl_generics#ident#ty_generics#where_clause { #[doc=#is_valid_doc] pubfn is_valid(value: i32) -> bool { match value { #(#is_valid,)*
_ => false,
}
}
#[deprecated = "Use the TryFrom<i32> implementation instead"] #[doc=#from_i32_doc] pubfn from_i32(value: i32) -> ::core::option::Option<#ident> { match value { #(#from,)*
_ => ::core::option::Option::None,
}
}
}
let variants = match input.data {
Data::Enum(DataEnum { variants, .. }) => variants,
Data::Struct(..) => bail!("Oneof can not be derived for a struct"),
Data::Union(..) => bail!("Oneof can not be derived for a union"),
};
let generics = &input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
// Map the variants into 'fields'. letmut fields: Vec<(Ident, Field)> = Vec::new(); for Variant {
attrs,
ident: variant_ident,
fields: variant_fields,
..
} in variants
{ let variant_fields = match variant_fields {
Fields::Unit => Punctuated::new(),
Fields::Named(FieldsNamed { named: fields, .. })
| Fields::Unnamed(FieldsUnnamed {
unnamed: fields, ..
}) => fields,
}; if variant_fields.len() != 1 {
bail!("Oneof enum variants must have a single field");
} match Field::new_oneof(attrs)? {
Some(field) => fields.push((variant_ident, field)),
None => bail!("invalid oneof variant: oneof variants may not be ignored"),
}
}
letmut tags = fields
.iter()
.flat_map(|&(ref variant_ident, ref field)| -> Result<u32, Error> { if field.tags().len() > 1 {
bail!( "invalid oneof variant {}::{}: oneof variants may only have a single tag",
ident,
variant_ident
);
}
Ok(field.tags()[0])
})
.collect::<Vec<_>>();
tags.sort_unstable();
tags.dedup(); if tags.len() != fields.len() {
panic!("invalid oneof {}: variants have duplicate tags", ident);
}
let encode = fields.iter().map(|&(ref variant_ident, ref field)| { let encode = field.encode(quote!(*value));
quote!(#ident::#variant_ident(ref value) => { #encode })
});
let merge = fields.iter().map(|&(ref variant_ident, ref field)| { let tag = field.tags()[0]; let merge = field.merge(quote!(value));
quote! { #tag => { match field {
::core::option::Option::Some(#ident::#variant_ident(refmut value)) => { #merge
},
_ => { letmut owned_value = ::core::default::Default::default(); let value = &mut owned_value; #merge.map(|_| *field = ::core::option::Option::Some(#ident::#variant_ident(owned_value)))
},
}
}
}
});
let encoded_len = fields.iter().map(|&(ref variant_ident, ref field)| { let encoded_len = field.encoded_len(quote!(*value));
quote!(#ident::#variant_ident(ref value) => #encoded_len)
});
let expanded = quote! { impl#impl_generics#ident#ty_generics#where_clause { /// Encodes the message to a buffer. pubfn encode<B>(&self, buf: &mut B) where B: ::prost::bytes::BufMut { match *self { #(#encode,)*
}
}
/// Decodes an instance of the message from a buffer, and merges it into self. pubfn merge<B>(
field: &mut ::core::option::Option<#ident#ty_generics>,
tag: u32,
wire_type: ::prost::encoding::WireType,
buf: &mut B,
ctx: ::prost::encoding::DecodeContext,
) -> ::core::result::Result<(), ::prost::DecodeError> where B: ::prost::bytes::Buf { match tag { #(#merge,)*
_ => unreachable!(concat!("invalid ", stringify!(#ident), " tag: {}"), tag),
}
}
/// Returns the encoded length of the message without a length delimiter. #[inline] pubfn encoded_len(&self) -> usize { match *self { #(#encoded_len,)*
}
}
}
}; let expanded = if skip_debug {
expanded
} else { let debug = fields.iter().map(|&(ref variant_ident, ref field)| { let wrapper = field.debug(quote!(*value));
quote!(#ident::#variant_ident(ref value) => { let wrapper = #wrapper;
f.debug_tuple(stringify!(#variant_ident))
.field(&wrapper)
.finish()
})
});
quote! { #expanded
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.