# tupley
## Intro
Extension for primitive tuple (Hlist based on recursive structure).
You could use it to contain elements with different types
## Struct
Basic structure:
```rust
struct Tuple<First, Tail>(First, Tail); // NonEmpty Tuple
struct Unit // Empty Tuple used as last element
impl TupleY for Unit {
const LEN: usize = 0;
/** **/
}
impl<First, Tail: TupleY> TupleY for Tuple<First, Tail> {
const LEN: usize = <Tail as TupleY>::LEN + 1;
/** ... **/
}
```
```rust
let t = tup!(1, 2.0, false);
// Tuple(1, Tuple(2.0, Tuple(false, Unit)))
```
## Usage
- create new tuple:
```rust
let t = tup!();
assert_eq!(t, Unit);
let t = tup!(1);
assert_eq!(t, Tuple(1, Unit));
let t = tup!(1, 2.0, "3");
assert_eq!(t, Tuple(1, Tuple(2.0, Tuple("3", Unit))));
```
- check empty:
```rust
let t = tup!();
assert!(t.is_empty());
let t = tup!(1, false);
assert!(!t.is_empty());
```
- pass on type:
```rust
let t = <tup_t!(i32, &str, bool)>::default();
// let t: tup_t!(i32, &str, bool) = Default::default();
assert_eq!(t, tup!(0, "", false));
```
- pattern macth:
```rust
let t = tup!();
let tup_pat!() = t;
let t = tup!(1);
let tup_pat!(a) = t;
assert_eq!(a, tup!(1));
let t = tup!("", 2, 3.0);
let tup_pat!(a, b, c) = t;
assert_eq!(a, "");
assert_eq!(b, 2);
assert_eq!(c, tup!(3.0));
// don't match anything
let t = tup!(1, 2, 3, 4, 5);
let tup_pat!(..) = t;
let t = tup!(1, 2.0, "", vec![1], true);
let tup_pat!(a, b, c) = t;
assert_eq!(a, 1);
assert_eq!(b, 2.0);
assert_eq!(c, tup!("", vec![1], true)); // match the rest all
```
- get length of every tuple:
```rust
let t = tup!();
assert_eq!(0, t.len());
let t = tup!(1, false);
assert_eq!(2, t.len());
let t = tup!(1, 2, 3);
assert_eq!(3, t.len());
```
- add/combine two tuples into one (or pushing back/front new element)
```rust
let t1 = tup!(1, 2);
let t2 = tup!(3.0, false, Some(1));
let t = t1 + t2;
assert_eq!(t, tup!(1, 2, 3.0, false, Some(1)));
let t = tup!();
let t = t.push_back(1);
let t = t.push_back("str");
let t = t.push_back(false);
assert_eq!(t, tup!(1, "str", false));
let t = tup!();
let t = t.push_front(1);
let t = t.push_front("str");
let t = t.push_front(false);
assert_eq!(t, tup!(false, "str", 1));
```
- functor map `as_ref`/`as_mut`/`to_some`/`to_ok`:
```rust
let t = tup!(1, "str", 3.0, false);
assert_eq!(t.as_ref(), tup!(&1, &"str", &3.0, &false));
let mut t = tup!(1, "str", 3.0, false);
assert_eq!(t.as_mut(), tup!(&mut 1, &mut "str", &mut 3.0, &mut false));
let t = tup!(1, "str", 3.0, false);
assert_eq!(t.to_some(), tup!(Some(1), Some("str"), Some(3.0), Some(false)));
let t = tup!(1, "str", 3.0, false);
assert_eq!(t.to_ok::<()>(), tup!(Ok(1), Ok("str"), Ok(3.0), Ok(false)));
```
- check length in compile-time for tuples passed in (using const generics):
```rust
let t = tup!(1, 2, 3);
fn eq_yes<T: TupleLenEq<3>>(_: T) {}
eq_yes(t);
fn gt_yes_1<T: TupleLenGt<3>>(_: T) {}
gt_yes_1(t);
fn gt_yes_2<T: TupleLenGt<2>>(_: T) {}
gt_yes_2(t);
// The following will failed in compile time
// fn gt_err<T: TupleLenGt<4>>(_: T) {} gt_err(t);
// fn eq_err<T: TupleLenEq<2>>(_: T) {} eq_err(t);
```
More work WIP.