summaryrefslogtreecommitdiffstats
path: root/third_party/rust/uniffi_checksum_derive/src
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-19 01:47:29 +0000
commit0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d (patch)
treea31f07c9bcca9d56ce61e9a1ffd30ef350d513aa /third_party/rust/uniffi_checksum_derive/src
parentInitial commit. (diff)
downloadfirefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.tar.xz
firefox-esr-0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d.zip
Adding upstream version 115.8.0esr.upstream/115.8.0esr
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/uniffi_checksum_derive/src')
-rw-r--r--third_party/rust/uniffi_checksum_derive/src/lib.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/third_party/rust/uniffi_checksum_derive/src/lib.rs b/third_party/rust/uniffi_checksum_derive/src/lib.rs
new file mode 100644
index 0000000000..2fefdb2574
--- /dev/null
+++ b/third_party/rust/uniffi_checksum_derive/src/lib.rs
@@ -0,0 +1,134 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#![cfg_attr(feature = "nightly", feature(proc_macro_expand))]
+
+//! Custom derive for uniffi_meta::Checksum
+
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, Attribute, Data, DeriveInput, Expr, ExprLit, Fields, Index, Lit};
+
+fn has_ignore_attribute(attrs: &[Attribute]) -> bool {
+ attrs.iter().any(|attr| {
+ if attr.path.is_ident("checksum_ignore") {
+ if !attr.tokens.is_empty() {
+ panic!("#[checksum_ignore] doesn't accept extra information");
+ }
+ true
+ } else {
+ false
+ }
+ })
+}
+
+#[proc_macro_derive(Checksum, attributes(checksum_ignore))]
+pub fn checksum_derive(input: TokenStream) -> TokenStream {
+ let input: DeriveInput = parse_macro_input!(input);
+
+ let name = input.ident;
+
+ let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
+
+ let code = match input.data {
+ Data::Enum(enum_)
+ if enum_.variants.len() == 1
+ && enum_
+ .variants
+ .iter()
+ .all(|variant| matches!(variant.fields, Fields::Unit)) =>
+ {
+ quote!()
+ }
+ Data::Enum(enum_) => {
+ let mut next_discriminant = 0u64;
+ let match_inner = enum_.variants.iter().map(|variant| {
+ let ident = &variant.ident;
+ if has_ignore_attribute(&variant.attrs) {
+ panic!("#[checksum_ignore] is not supported in enums");
+ }
+ match &variant.discriminant {
+ Some((_, Expr::Lit(ExprLit { lit: Lit::Int(value), .. }))) => {
+ next_discriminant = value.base10_parse::<u64>().unwrap();
+ }
+ Some(_) => {
+ panic!("#[derive(Checksum)] doesn't support non-numeric explicit discriminants in enums");
+ }
+ None => {}
+ }
+ let discriminant = quote! { state.write(&#next_discriminant.to_le_bytes()) };
+ next_discriminant += 1;
+ match &variant.fields {
+ Fields::Unnamed(fields) => {
+ let field_idents = fields
+ .unnamed
+ .iter()
+ .enumerate()
+ .map(|(num, _)| format_ident!("__self_{}", num));
+ let field_stmts = field_idents
+ .clone()
+ .map(|ident| quote! { Checksum::checksum(#ident, state); });
+ quote! {
+ Self::#ident(#(#field_idents,)*) => {
+ #discriminant;
+ #(#field_stmts)*
+ }
+ }
+ }
+ Fields::Named(fields) => {
+ let field_idents = fields
+ .named
+ .iter()
+ .map(|field| field.ident.as_ref().unwrap());
+ let field_stmts = field_idents
+ .clone()
+ .map(|ident| quote! { Checksum::checksum(#ident, state); });
+ quote! {
+ Self::#ident { #(#field_idents,)* } => {
+ #discriminant;
+ #(#field_stmts)*
+ }
+ }
+ }
+ Fields::Unit => quote! { Self::#ident => #discriminant, },
+ }
+ });
+ quote! {
+ match self {
+ #(#match_inner)*
+ }
+ }
+ }
+ Data::Struct(struct_) => {
+ let stmts = struct_
+ .fields
+ .iter()
+ .enumerate()
+ .filter_map(|(num, field)| {
+ (!has_ignore_attribute(&field.attrs)).then(|| match field.ident.as_ref() {
+ Some(ident) => quote! { Checksum::checksum(&self.#ident, state); },
+ None => {
+ let i = Index::from(num);
+ quote! { Checksum::checksum(&self.#i, state); }
+ }
+ })
+ });
+ quote! {
+ #(#stmts)*
+ }
+ }
+ Data::Union(_) => {
+ panic!("#[derive(Checksum)] is not supported for unions");
+ }
+ };
+
+ quote! {
+ #[automatically_derived]
+ impl #impl_generics Checksum for #name #ty_generics #where_clause {
+ fn checksum<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
+ #code
+ }
+ }
+ }
+ .into()
+}