summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock52
-rw-r--r--Cargo.toml3
-rw-r--r--examples/split.rs20
-rw-r--r--src/lib.rs137
-rw-r--r--varihappy-macros/Cargo.toml10
-rw-r--r--varihappy-macros/src/lib.rs15
6 files changed, 175 insertions, 62 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 133c06e..ea68854 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3,5 +3,57 @@
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<T> = <T as Tuple1>::Item0;
+type RestOf<T> = <<<<T as Tuple1>::Rest as Tuple>::Reversed as Tuple1>::Rest as Tuple>::Reversed;
+type TailOf<T> = <<<T as Tuple1>::Rest as Tuple>::Reversed as Tuple1>::Item0;
+
+fn split<T>(tuple: T) -> (HeadOf<T>, RestOf<T>, TailOf<T>)
+where
+ T: Tuple2,
+ <<T as Tuple1>::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) -> <Self as Tuple2>::Rest;
+macro_rules! impl_tuple {
+ (
+ A, $($letter: ident),* => $($letter_reverse: ident),*;
+ 0, $($number: tt),* => $($number_reverse: tt),*
+ ) => {
+ impl<A,$($letter),*> 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<A, $($letter),*> 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<A> 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<A, B> 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<A> Tuple1 for (A,) {
fn into_rest(self) -> Self::Rest {}
}
-impl<A, B> Tuple1 for (A, B) {
- type Item0 = A;
-
- type Rest = (B,);
-
- fn into_0(self) -> Self::Item0 {
- self.0
- }
-
- fn split_into(self) -> (Self::Item0, <Self as Tuple1>::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) -> <Self as $trait_name>::Rest;
+ }
+
+ impl<R: Tuple1, T: $trait_minus1<Rest = R>> $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) -> <Self as $trait_name>::Rest {
+ $trait_minus1::into_rest(self).into_rest()
+ }
+ }
+ };
}
-impl<R: Tuple1, T: Tuple1<Rest = R>> 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) -> <Self as Tuple2>::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
+}