summaryrefslogtreecommitdiffstats
path: root/vendor/zerovec-derive/src/utils.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:18:32 +0000
commit4547b622d8d29df964fa2914213088b148c498fc (patch)
tree9fc6b25f3c3add6b745be9a2400a6e96140046e9 /vendor/zerovec-derive/src/utils.rs
parentReleasing progress-linux version 1.66.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-4547b622d8d29df964fa2914213088b148c498fc.tar.xz
rustc-4547b622d8d29df964fa2914213088b148c498fc.zip
Merging upstream version 1.67.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/zerovec-derive/src/utils.rs')
-rw-r--r--vendor/zerovec-derive/src/utils.rs277
1 files changed, 277 insertions, 0 deletions
diff --git a/vendor/zerovec-derive/src/utils.rs b/vendor/zerovec-derive/src/utils.rs
new file mode 100644
index 000000000..24bb56759
--- /dev/null
+++ b/vendor/zerovec-derive/src/utils.rs
@@ -0,0 +1,277 @@
+// This file is part of ICU4X. For terms of use, please see the file
+// called LICENSE at the top level of the ICU4X source tree
+// (online at: https://github.com/unicode-org/icu4x/blob/main/LICENSE ).
+
+use quote::quote;
+
+use proc_macro2::Span;
+use proc_macro2::TokenStream as TokenStream2;
+use syn::parse::{Parse, ParseStream};
+use syn::punctuated::Punctuated;
+use syn::spanned::Spanned;
+use syn::{parenthesized, parse2, Attribute, Error, Field, Fields, Ident, Index, Result, Token};
+
+// Check that there are repr attributes satisfying the given predicate
+pub fn has_valid_repr(attrs: &[Attribute], predicate: impl Fn(&Ident) -> bool + Copy) -> bool {
+ attrs
+ .iter()
+ .filter(|a| a.path.get_ident().map(|a| a == "repr").unwrap_or(false))
+ .any(|a| {
+ parse2::<IdentListAttribute>(a.tokens.clone())
+ .ok()
+ .and_then(|s| s.idents.iter().find(|s| predicate(s)).map(|_| ()))
+ .is_some()
+ })
+}
+
+// An attribute that is a list of idents
+struct IdentListAttribute {
+ idents: Punctuated<Ident, Token![,]>,
+}
+
+impl Parse for IdentListAttribute {
+ fn parse(input: ParseStream) -> Result<Self> {
+ let content;
+ let _paren = parenthesized!(content in input);
+ Ok(IdentListAttribute {
+ idents: content.parse_terminated(Ident::parse)?,
+ })
+ }
+}
+
+/// Given a set of entries for struct field definitions to go inside a `struct {}` definition,
+/// wrap in a () or {} based on the type of field
+pub fn wrap_field_inits(streams: &[TokenStream2], fields: &Fields) -> TokenStream2 {
+ match *fields {
+ Fields::Named(_) => quote!( { #(#streams),* } ),
+ Fields::Unnamed(_) => quote!( ( #(#streams),* ) ),
+ Fields::Unit => {
+ unreachable!("#[make_(var)ule] should have already checked that there are fields")
+ }
+ }
+}
+
+/// Return a semicolon token if necessary after the struct definition
+pub fn semi_for(f: &Fields) -> TokenStream2 {
+ if let Fields::Unnamed(..) = *f {
+ quote!(;)
+ } else {
+ quote!()
+ }
+}
+
+/// Returns the repr attribute to be applied to the resultant ULE or VarULE type
+pub fn repr_for(f: &Fields) -> TokenStream2 {
+ if f.len() == 1 {
+ quote!(transparent)
+ } else {
+ quote!(packed)
+ }
+}
+
+fn suffixed_ident(name: &str, suffix: usize, s: Span) -> Ident {
+ Ident::new(&format!("{name}_{suffix}"), s)
+}
+
+/// Given an iterator over ULE or AsULE struct fields, returns code that calculates field sizes and generates a line
+/// of code per field based on the per_field_code function (whose parameters are the field, the identifier of the const
+/// for the previous offset, the identifier for the const for the next offset, and the field index)
+pub(crate) fn generate_per_field_offsets<'a>(
+ fields: &[FieldInfo<'a>],
+ // Whether the fields are ULE types or AsULE (and need conversion)
+ fields_are_asule: bool,
+ // (field, prev_offset_ident, size_ident)
+ mut per_field_code: impl FnMut(&FieldInfo<'a>, &Ident, &Ident) -> TokenStream2, /* (code, remaining_offset) */
+) -> (TokenStream2, syn::Ident) {
+ let mut prev_offset_ident = Ident::new("ZERO", Span::call_site());
+ let mut code = quote!(
+ const ZERO: usize = 0;
+ );
+
+ for (i, field_info) in fields.iter().enumerate() {
+ let field = &field_info.field;
+ let ty = &field.ty;
+ let ty = if fields_are_asule {
+ quote!(<#ty as zerovec::ule::AsULE>::ULE)
+ } else {
+ quote!(#ty)
+ };
+ let new_offset_ident = suffixed_ident("OFFSET", i, field.span());
+ let size_ident = suffixed_ident("SIZE", i, field.span());
+ let pf_code = per_field_code(field_info, &prev_offset_ident, &size_ident);
+ code = quote! {
+ #code;
+ const #size_ident: usize = ::core::mem::size_of::<#ty>();
+ const #new_offset_ident: usize = #prev_offset_ident + #size_ident;
+ #pf_code;
+ };
+
+ prev_offset_ident = new_offset_ident;
+ }
+
+ (code, prev_offset_ident)
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct FieldInfo<'a> {
+ pub accessor: TokenStream2,
+ pub field: &'a Field,
+ pub index: usize,
+}
+
+impl<'a> FieldInfo<'a> {
+ pub fn make_list(iter: impl Iterator<Item = &'a Field>) -> Vec<Self> {
+ iter.enumerate()
+ .map(|(i, field)| Self::new_for_field(field, i))
+ .collect()
+ }
+
+ pub fn new_for_field(f: &'a Field, index: usize) -> Self {
+ if let Some(ref i) = f.ident {
+ FieldInfo {
+ accessor: quote!(#i),
+ field: f,
+ index,
+ }
+ } else {
+ let idx = Index::from(index);
+ FieldInfo {
+ accessor: quote!(#idx),
+ field: f,
+ index,
+ }
+ }
+ }
+
+ /// Get the code for setting this field in struct decl/brace syntax
+ ///
+ /// Use self.accessor for dot-notation accesses
+ pub fn setter(&self) -> TokenStream2 {
+ if let Some(ref i) = self.field.ident {
+ quote!(#i: )
+ } else {
+ quote!()
+ }
+ }
+}
+
+/// Extracts all `zerovec::name(..)` attribute
+pub fn extract_parenthetical_zerovec_attrs(
+ attrs: &mut Vec<Attribute>,
+ name: &str,
+) -> Result<Vec<Ident>> {
+ let mut ret = vec![];
+ let mut error = None;
+ attrs.retain(|a| {
+ // skip the "zerovec" part
+ let second_segment = a.path.segments.iter().nth(1);
+
+ if let Some(second) = second_segment {
+ if second.ident == name {
+ let list = match parse2::<IdentListAttribute>(a.tokens.clone()) {
+ Ok(l) => l,
+ Err(_) => {
+ error = Some(Error::new(
+ a.span(),
+ "#[zerovec::name(..)] takes in a comma separated list of identifiers",
+ ));
+ return false;
+ }
+ };
+ ret.extend(list.idents.iter().cloned());
+ return false;
+ }
+ }
+
+ true
+ });
+
+ if let Some(error) = error {
+ return Err(error);
+ }
+ Ok(ret)
+}
+
+/// Removes all attributes with `zerovec` in the name and places them in a separate vector
+pub fn extract_zerovec_attributes(attrs: &mut Vec<Attribute>) -> Vec<Attribute> {
+ let mut ret = vec![];
+ attrs.retain(|a| {
+ if a.path.segments.len() == 2 && a.path.segments[0].ident == "zerovec" {
+ ret.push(a.clone());
+ return false;
+ }
+ true
+ });
+ ret
+}
+
+#[derive(Default, Copy, Clone)]
+pub struct ZeroVecAttrs {
+ pub skip_kv: bool,
+ pub skip_ord: bool,
+ pub serialize: bool,
+ pub deserialize: bool,
+ pub debug: bool,
+}
+
+/// Removes all known zerovec:: attributes from attrs and validates them
+pub fn extract_attributes_common(
+ attrs: &mut Vec<Attribute>,
+ span: Span,
+ is_var: bool,
+) -> Result<ZeroVecAttrs> {
+ let mut zerovec_attrs = extract_zerovec_attributes(attrs);
+
+ let derive = extract_parenthetical_zerovec_attrs(&mut zerovec_attrs, "derive")?;
+ let skip = extract_parenthetical_zerovec_attrs(&mut zerovec_attrs, "skip_derive")?;
+
+ let name = if is_var { "make_varule" } else { "make_ule" };
+
+ if let Some(attr) = zerovec_attrs.get(0) {
+ return Err(Error::new(
+ attr.span(),
+ format!("Found unknown or duplicate attribute for #[{name}]"),
+ ));
+ }
+
+ let mut attrs = ZeroVecAttrs::default();
+
+ for ident in derive {
+ if ident == "Serialize" {
+ attrs.serialize = true;
+ } else if ident == "Deserialize" {
+ attrs.deserialize = true;
+ } else if ident == "Debug" {
+ attrs.debug = true;
+ } else {
+ return Err(Error::new(
+ ident.span(),
+ format!(
+ "Found unknown derive attribute for #[{name}]: #[zerovec::derive({ident})]"
+ ),
+ ));
+ }
+ }
+
+ for ident in skip {
+ if ident == "ZeroMapKV" {
+ attrs.skip_kv = true;
+ } else if ident == "Ord" {
+ attrs.skip_ord = true;
+ } else {
+ return Err(Error::new(
+ ident.span(),
+ format!("Found unknown derive attribute for #[{name}]: #[zerovec::skip_derive({ident})]"),
+ ));
+ }
+ }
+
+ if (attrs.serialize || attrs.deserialize) && !is_var {
+ return Err(Error::new(
+ span,
+ "#[make_ule] does not support #[zerovec::derive(Serialize, Deserialize)]",
+ ));
+ }
+
+ Ok(attrs)
+}