From 3b3428d67ec465ee860c9cafcb10b99a2a2d37ec Mon Sep 17 00:00:00 2001 From: Mica White Date: Mon, 11 May 2026 15:02:39 -0400 Subject: Simple macros --- Cargo.lock | 52 +++++++++++++++++ Cargo.toml | 3 + examples/split.rs | 20 +++++++ src/lib.rs | 137 ++++++++++++++++++++++++-------------------- varihappy-macros/Cargo.toml | 10 ++++ varihappy-macros/src/lib.rs | 15 +++++ 6 files changed, 175 insertions(+), 62 deletions(-) create mode 100644 examples/split.rs create mode 100644 varihappy-macros/Cargo.toml create mode 100644 varihappy-macros/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 133c06e..ea68854 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,58 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +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" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + [[package]] name = "varihappy" version = "0.1.0" + +[[package]] +name = "varihappy-macros" +version = "0.1.0" +dependencies = [ + "proc_macros", +] diff --git a/Cargo.toml b/Cargo.toml index 7308a60..565a11b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,4 +3,7 @@ name = "varihappy" version = "0.1.0" edition = "2024" +[workspace] +members = ["varihappy-macros"] + [dependencies] diff --git a/examples/split.rs b/examples/split.rs new file mode 100644 index 0000000..c2f6b82 --- /dev/null +++ b/examples/split.rs @@ -0,0 +1,20 @@ +use varihappy::{Tuple, Tuple1, Tuple2}; + +type HeadOf = ::Item0; +type RestOf = <<<::Rest as Tuple>::Reversed as Tuple1>::Rest as Tuple>::Reversed; +type TailOf = <<::Rest as Tuple>::Reversed as Tuple1>::Item0; + +fn split(tuple: T) -> (HeadOf, RestOf, TailOf) +where + T: Tuple2, + <::Rest as Tuple>::Reversed: Tuple1, +{ + let (head, rest) = tuple.split_into(); + let (tail, rest) = rest.rev().split_into(); + (head, rest.rev(), tail) +} + +fn main() { + let (_head, _rest, _tail): (i32, (), &str) = split((42, "foo")); + let (_head, _rest, _tail): (i32, (f64, bool, ()), &str) = split((42, 12.3, false, (), "foo")); +} diff --git a/src/lib.rs b/src/lib.rs index a7146b8..90bec23 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,12 +22,45 @@ pub trait Tuple1: Tuple { fn into_rest(self) -> Self::Rest; } -pub trait Tuple2: Tuple1 { - type Item1; - type Rest: Tuple; - - fn into_1(self) -> Self::Item1; - fn into_rest(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 () { @@ -62,38 +95,11 @@ impl Tuple for (A,) { fn as_ref(&self) -> Self::AsRef<'_> { (&self.0,) } - fn as_mut(&mut self) -> Self::AsMut<'_> { (&mut self.0,) } - - fn rev(self) -> Self::Reversed { - (self.0,) - } -} - -impl Tuple for (A, B) { - type AsRef<'a> - = (&'a A, &'a B) - where - Self: 'a; - type AsMut<'a> - = (&'a mut A, &'a mut B) - where - Self: 'a; - - type Reversed = (B, A); - - fn as_ref(&self) -> Self::AsRef<'_> { - (&self.0, &self.1) - } - - fn as_mut(&mut self) -> Self::AsMut<'_> { - (&mut self.0, &mut self.1) - } - fn rev(self) -> Self::Reversed { - (self.1, self.0) + self } } @@ -112,33 +118,40 @@ impl Tuple1 for (A,) { fn into_rest(self) -> Self::Rest {} } -impl Tuple1 for (A, B) { - type Item0 = A; - - type Rest = (B,); - - fn into_0(self) -> Self::Item0 { - self.0 - } - - fn split_into(self) -> (Self::Item0, ::Rest) { - (self.0, (self.1,)) - } - - fn into_rest(self) -> Self::Rest { - (self.1,) - } +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! tuple_trait { + (trait $trait_name: ident for $trait_minus1: ident { + type $item_name: ident; + fn $item_getter: ident; + }) => { + pub trait $trait_name: $trait_minus1 { + type $item_name; + type Rest: Tuple; + + fn $item_getter(self) -> Self::$item_name; + fn into_rest(self) -> ::Rest; + } + + impl> $trait_name for T { + type $item_name = R::Item0; + type Rest = R::Rest; + + fn $item_getter(self) -> Self::$item_name { + $trait_minus1::into_rest(self).into_0() + } + + fn into_rest(self) -> ::Rest { + $trait_minus1::into_rest(self).into_rest() + } + } + }; } -impl> Tuple2 for T { - type Item1 = R::Item0; - type Rest = R::Rest; - - fn into_1(self) -> Self::Item1 { - self.into_rest().into_0() - } - - fn into_rest(self) -> ::Rest { - self.into_rest().into_rest() - } -} +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; }); diff --git a/varihappy-macros/Cargo.toml b/varihappy-macros/Cargo.toml new file mode 100644 index 0000000..968ce85 --- /dev/null +++ b/varihappy-macros/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "varihappy-macros" +version = "0.1.0" +edition = "2024" + +[lib] +proc-macro = true + +[dependencies] +proc_macros = "0.1.0" diff --git a/varihappy-macros/src/lib.rs b/varihappy-macros/src/lib.rs new file mode 100644 index 0000000..561962c --- /dev/null +++ b/varihappy-macros/src/lib.rs @@ -0,0 +1,15 @@ +use proc_macro::{Ident, Span, TokenStream, TokenTree}; + +#[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()); + } + } + + let mut stream = TokenStream::new(); + stream.extend([Ident::new(&buffer, Span::call_site())]); + stream +} -- cgit v1.2.3