ai generated

This commit is contained in:
Intege-rs
2026-02-03 03:33:48 -05:00
commit f8e3e4ae8e
8 changed files with 801 additions and 0 deletions

12
hash2_derive/Cargo.toml Normal file
View File

@@ -0,0 +1,12 @@
[package]
name = "hash2_derive"
version = "0.1.0"
edition = "2024"
[lib]
proc-macro = true
[dependencies]
syn = { version = "2", features = ["full"] }
quote = "1"
proc-macro2 = "1"

126
hash2_derive/src/lib.rs Normal file
View File

@@ -0,0 +1,126 @@
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, Data, DeriveInput, Fields, GenericParam, Generics};
#[proc_macro_derive(Hash2)]
pub fn derive_hash2(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
let name = &input.ident;
let generics = &input.generics;
// Extract field hashing logic
let hash_fields = match &input.data {
Data::Struct(data) => {
match &data.fields {
Fields::Named(fields) => {
let field_names = fields.named.iter().map(|f| &f.ident);
quote! {
#(
::hash2::Hash2::hash(&self.#field_names, state);
)*
}
}
Fields::Unnamed(fields) => {
let field_indices = (0..fields.unnamed.len()).map(syn::Index::from);
quote! {
#(
::hash2::Hash2::hash(&self.#field_indices, state);
)*
}
}
Fields::Unit => {
quote! {}
}
}
}
Data::Enum(data) => {
let variants = data.variants.iter().map(|variant| {
let variant_name = &variant.ident;
match &variant.fields {
Fields::Named(fields) => {
let field_names: Vec<_> = fields.named.iter().map(|f| &f.ident).collect();
let field_names2 = field_names.clone();
quote! {
#name::#variant_name { #(#field_names),* } => {
#(
::hash2::Hash2::hash(#field_names2, state);
)*
}
}
}
Fields::Unnamed(fields) => {
let field_names: Vec<_> = (0..fields.unnamed.len())
.map(|i| syn::Ident::new(&format!("f{}", i), proc_macro2::Span::call_site()))
.collect();
let field_names2 = field_names.clone();
quote! {
#name::#variant_name(#(#field_names),*) => {
#(
::hash2::Hash2::hash(#field_names2, state);
)*
}
}
}
Fields::Unit => {
quote! {
#name::#variant_name => {}
}
}
}
});
quote! {
match self {
#(#variants)*
}
}
}
Data::Union(_) => {
panic!("Hash2 cannot be derived for unions");
}
};
// Build where clause with Hash2 bounds for generic types
let where_clause = build_where_clause(generics);
// Split generics for impl
let (impl_generics, ty_generics, _) = generics.split_for_impl();
let expanded = quote! {
impl #impl_generics ::hash2::Hash2 for #name #ty_generics #where_clause {
fn hash<H: ::hash2::Hasher>(&self, state: &mut H) {
#hash_fields
}
}
};
TokenStream::from(expanded)
}
fn build_where_clause(generics: &Generics) -> proc_macro2::TokenStream {
let mut predicates = Vec::new();
// Add Hash2 bound for each type parameter (but not lifetimes)
for param in &generics.params {
if let GenericParam::Type(type_param) = param {
let ident = &type_param.ident;
predicates.push(quote! { #ident: ::hash2::Hash2 });
}
}
// Include existing where predicates
if let Some(where_clause) = &generics.where_clause {
for predicate in &where_clause.predicates {
predicates.push(quote! { #predicate });
}
}
if predicates.is_empty() {
quote! {}
} else {
quote! {
where #(#predicates),*
}
}
}