From fd835b4ce895d83940cca0107fd03c7b035506ac Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 11 May 2026 22:49:50 -0400 Subject: Use proc macros to expand the number of traits --- Cargo.lock | 17 ++---- Cargo.toml | 1 + src/lib.rs | 134 ++++++++++++++++++++++++++++--------------- varihappy-macros/Cargo.toml | 4 +- varihappy-macros/src/lib.rs | 137 ++++++++++++++++++++++++++++++++++++++++++-- 5 files changed, 230 insertions(+), 63 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ea68854..7aee7ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,16 +11,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c8ef2e003e8285b3fc12d313756ea15b6de201013f917530728358882dec07f" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "quote" version = "1.0.45" @@ -50,10 +40,15 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "varihappy" version = "0.1.0" +dependencies = [ + "varihappy-macros", +] [[package]] name = "varihappy-macros" version = "0.1.0" dependencies = [ - "proc_macros", + "proc-macro2", + "quote", + "syn", ] diff --git a/Cargo.toml b/Cargo.toml index 565a11b..2c34d0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,4 @@ edition = "2024" members = ["varihappy-macros"] [dependencies] +varihappy-macros = { path = "varihappy-macros" } diff --git a/src/lib.rs b/src/lib.rs index 90bec23..7bd5342 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,8 @@ +use varihappy_macros::{ + reverse_expr_type, reverse_tuple_type, tuple_expr_len_rest, tuple_expr_mut, tuple_expr_ref, + tuple_type_len, tuple_type_len_rest, +}; + pub trait Tuple { type AsRef<'a>: Tuple where @@ -22,47 +27,6 @@ pub trait Tuple1: Tuple { fn into_rest(self) -> Self::Rest; } -macro_rules! impl_tuple { - ( - A, $($letter: ident),* => $($letter_reverse: ident),*; - 0, $($number: tt),* => $($number_reverse: tt),* - ) => { - impl Tuple for (A,$($letter,)*) { - type AsRef<'a> = (&'a A,$(&'a $letter,)*) where Self: 'a; - type AsMut<'a> = (&'a mut A,$(&'a mut $letter,)*) where Self: 'a; - type Reversed = ($($letter_reverse,)*); - - fn as_ref(&self) -> Self::AsRef<'_> { - (&self.0,$(&self.$number,)*) - } - - fn as_mut(&mut self) -> Self::AsMut<'_> { - (&mut self.0,$(&mut self.$number,)*) - } - - fn rev(self) -> Self::Reversed { - ($(self.$number_reverse,)*) - } - } - - impl Tuple1 for (A, $($letter,)*) { - type Item0 = A; - type Rest = ($($letter,)*); - - fn into_0(self) -> Self::Item0 { - self.0 - } - fn split_into(self) -> (Self::Item0, Self::Rest) { - (self.0, ($(self.$number,)*)) - } - - fn into_rest(self) -> Self::Rest { - ($(self.$number,)*) - } - } - }; -} - impl Tuple for () { type AsRef<'a> = () @@ -118,10 +82,69 @@ impl Tuple1 for (A,) { fn into_rest(self) -> Self::Rest {} } -impl_tuple!(A, B => B, A; 0, 1 => 1, 0); -impl_tuple!(A, B, C => C, B, A; 0, 1, 2 => 2, 1, 0); -impl_tuple!(A, B, C, D => D, C, B, A; 0, 1, 2, 3 => 3, 2, 1, 0); -impl_tuple!(A, B, C, D, E => E, D, C, B, A; 0, 1, 2, 3, 4 => 4, 3, 2, 1, 0); +macro_rules! impl_tuple { + ($length: expr; $($letter: ident),*) => { + impl<$($letter),*> Tuple for tuple_type_len!($length) { + type AsRef<'a> = ($(&'a $letter,)*) where Self: 'a; + type AsMut<'a> = ($(&'a mut $letter,)*) where Self: 'a; + type Reversed = reverse_tuple_type!($length); + + fn as_ref(&self) -> Self::AsRef<'_> { + tuple_expr_ref!($length) + } + + fn as_mut(&mut self) -> Self::AsMut<'_> { + tuple_expr_mut!($length) + } + + fn rev(self) -> Self::Reversed { + reverse_expr_type!($length) + } + } + + impl<$($letter),*> Tuple1 for tuple_type_len!($length) { + type Item0 = A; + type Rest = tuple_type_len_rest!($length); + + fn into_0(self) -> Self::Item0 { + self.0 + } + fn split_into(self) -> (Self::Item0, Self::Rest) { + (self.0, tuple_expr_len_rest!($length)) + } + + fn into_rest(self) -> Self::Rest { + tuple_expr_len_rest!($length) + } + } + }; +} + +impl_tuple!(2; A, B); +impl_tuple!(3; A, B, C); +impl_tuple!(4; A, B, C, D); +impl_tuple!(5; A, B, C, D, E); +impl_tuple!(6; A, B, C, D, E, F); +impl_tuple!(7; A, B, C, D, E, F, G); +impl_tuple!(8; A, B, C, D, E, F, G, H); +impl_tuple!(9; A, B, C, D, E, F, G, H, I); +impl_tuple!(10; A, B, C, D, E, F, G, H, I, J); +impl_tuple!(11; A, B, C, D, E, F, G, H, I, J, K); +impl_tuple!(12; A, B, C, D, E, F, G, H, I, J, K, L); +impl_tuple!(13; A, B, C, D, E, F, G, H, I, J, K, L, M); +impl_tuple!(14; A, B, C, D, E, F, G, H, I, J, K, L, M, N); +impl_tuple!(15; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); +impl_tuple!(16; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); +impl_tuple!(17; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q); +impl_tuple!(18; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R); +impl_tuple!(19; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); +impl_tuple!(20; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T); +impl_tuple!(21; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U); +impl_tuple!(22; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V); +impl_tuple!(23; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W); +impl_tuple!(24; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X); +impl_tuple!(25; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y); +impl_tuple!(26; A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z); macro_rules! tuple_trait { (trait $trait_name: ident for $trait_minus1: ident { @@ -155,3 +178,24 @@ tuple_trait!(trait Tuple2 for Tuple1 { type Item1; fn into_1; }); tuple_trait!(trait Tuple3 for Tuple2 { type Item2; fn into_2; }); tuple_trait!(trait Tuple4 for Tuple3 { type Item3; fn into_3; }); tuple_trait!(trait Tuple5 for Tuple4 { type Item4; fn into_4; }); +tuple_trait!(trait Tuple6 for Tuple5 { type Item5; fn into_5; }); +tuple_trait!(trait Tuple7 for Tuple6 { type Item6; fn into_6; }); +tuple_trait!(trait Tuple8 for Tuple7 { type Item7; fn into_7; }); +tuple_trait!(trait Tuple9 for Tuple8 { type Item8; fn into_8; }); +tuple_trait!(trait Tuple10 for Tuple9 { type Item9; fn into_9; }); +tuple_trait!(trait Tuple11 for Tuple10 { type Item10; fn into_10; }); +tuple_trait!(trait Tuple12 for Tuple11 { type Item11; fn into_11; }); +tuple_trait!(trait Tuple13 for Tuple12 { type Item12; fn into_12; }); +tuple_trait!(trait Tuple14 for Tuple13 { type Item13; fn into_13; }); +tuple_trait!(trait Tuple15 for Tuple14 { type Item14; fn into_14; }); +tuple_trait!(trait Tuple16 for Tuple15 { type Item15; fn into_15; }); +tuple_trait!(trait Tuple17 for Tuple16 { type Item16; fn into_16; }); +tuple_trait!(trait Tuple18 for Tuple17 { type Item17; fn into_17; }); +tuple_trait!(trait Tuple19 for Tuple18 { type Item18; fn into_18; }); +tuple_trait!(trait Tuple20 for Tuple19 { type Item19; fn into_19; }); +tuple_trait!(trait Tuple21 for Tuple20 { type Item20; fn into_20; }); +tuple_trait!(trait Tuple22 for Tuple21 { type Item21; fn into_21; }); +tuple_trait!(trait Tuple23 for Tuple22 { type Item22; fn into_22; }); +tuple_trait!(trait Tuple24 for Tuple23 { type Item23; fn into_23; }); +tuple_trait!(trait Tuple25 for Tuple24 { type Item24; fn into_24; }); +tuple_trait!(trait Tuple26 for Tuple25 { type Item25; fn into_25; }); diff --git a/varihappy-macros/Cargo.toml b/varihappy-macros/Cargo.toml index 968ce85..3999ad5 100644 --- a/varihappy-macros/Cargo.toml +++ b/varihappy-macros/Cargo.toml @@ -7,4 +7,6 @@ edition = "2024" proc-macro = true [dependencies] -proc_macros = "0.1.0" +proc-macro2 = "1" +syn = "2" +quote = "1" diff --git a/varihappy-macros/src/lib.rs b/varihappy-macros/src/lib.rs index 561962c..522d333 100644 --- a/varihappy-macros/src/lib.rs +++ b/varihappy-macros/src/lib.rs @@ -1,15 +1,140 @@ -use proc_macro::{Ident, Span, TokenStream, TokenTree}; +extern crate proc_macro; + +use proc_macro::TokenStream; +use proc_macro2::{Ident, Literal, Span}; +use quote::quote; +use syn::{Field, LitInt}; #[proc_macro] pub fn concat_idents(input: TokenStream) -> TokenStream { let mut buffer = String::new(); for token in input { - if let TokenTree::Ident(identifier) = token { - buffer.push_str(&identifier.to_string()); - } + buffer.push_str(&token.to_string()); } - let mut stream = TokenStream::new(); + let mut stream = proc_macro2::TokenStream::new(); stream.extend([Ident::new(&buffer, Span::call_site())]); - stream + stream.into() +} + +#[proc_macro] +pub fn number_to_generic(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let identifier = Ident::new( + match number { + 0 => "A", + 1 => "B", + 2 => "C", + 3 => "D", + 4 => "E", + 5 => "F", + 6 => "G", + 7 => "H", + 8 => "I", + 9 => "J", + 10 => "K", + 11 => "L", + 12 => "M", + 13 => "N", + 14 => "O", + 15 => "P", + 16 => "Q", + 17 => "R", + 18 => "S", + 19 => "T", + 20 => "U", + 21 => "V", + 22 => "W", + 23 => "X", + 24 => "Y", + 25 => "Z", + _ => panic!("Expected a number less than 26"), + }, + Span::call_site(), + ); + + quote! { #identifier }.into() +} + +#[proc_macro] +pub fn tuple_type_len(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = 0..number; + quote! { (#(::varihappy_macros::number_to_generic!(#num),)*) }.into() +} + +#[proc_macro] +pub fn tuple_type_ref(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = 0..number; + quote! { (#(&'a ::varihappy_macros::number_to_generic!(#num),)*) }.into() +} + +#[proc_macro] +pub fn tuple_type_mut(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = 0..number; + quote! { (#(&'a mut ::varihappy_macros::number_to_generic!(#num),)*) }.into() +} + +#[proc_macro] +pub fn reverse_tuple_type(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = (0..number).rev(); + quote! { (#(::varihappy_macros::number_to_generic!(#num),)*) }.into() +} + +#[proc_macro] +pub fn tuple_type_len_rest(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = 1..number; + quote! { (#(::varihappy_macros::number_to_generic!(#num),)*) }.into() +} + +#[proc_macro] +pub fn tuple_expr_ref(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = (0..number).map(Literal::u128_unsuffixed); + quote! { (#(&self.#num,)*) }.into() +} + +#[proc_macro] +pub fn tuple_expr_mut(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = (0..number).map(Literal::u128_unsuffixed); + quote! { (#(&mut self.#num,)*) }.into() +} + +#[proc_macro] +pub fn reverse_expr_type(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = (0..number).rev().map(Literal::u128_unsuffixed); + quote! { (#(self.#num,)*) }.into() +} + +#[proc_macro] +pub fn tuple_expr_len_rest(input: TokenStream) -> TokenStream { + let number = syn::parse_macro_input!(input as LitInt); + let number: u128 = number.base10_parse().expect("a number 0..=u128::MAX"); + + let num = (1..number).map(Literal::u128_unsuffixed); + quote! { (#(self.#num,)*) }.into() } -- cgit v1.2.3