Extension for primitive tuple (Hlist based on recursive structure).
You could use it to contain elements with different types.
Basic structure:
// NonEmpty Tuple
struct Tuple<First, Tail>(First, Tail);
// Empty Tuple used as last element
struct Unit;
trait TupleY {
const LEN: usize;
// ......
// ......
}
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;
// ......
// ......
}
use tupley::prelude::*;
let t = tup!(1, 2.0, false);
// Tuple(1, Tuple(2.0, Tuple(false, Unit)))
- generate new Tuple:
use tupley::prelude::*;
fn tuple_new() {
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:
use tupley::prelude::*;
fn tuple_is_empty() {
let t = tup!();
assert!(t.is_empty());
let t = tup!(1, false);
assert!(!t.is_empty());
}
- generate new Tuple type:
use tupley::prelude::*;
fn tuple_type() {
let t = <tup_t!(i32, &str, bool)>::default();
assert_eq!(t, tup!(0, "", false));
let t: tup_t!(i32, &str, bool) = Default::default();
assert_eq!(t, tup!(0, "", false));
#[derive(Default, Debug, PartialEq, Eq)]
struct Wrapper<'a> {
a: tup_t!(i32, i32),
b: tup_t!(&'a str, bool),
}
let t = Wrapper::default();
assert_eq!(t, Wrapper{
a: tup!(0, 0),
b: tup!("", false),
})
}
- generate Tuple pattern for macthing:
use tupley::prelude::*;
fn tuple_pattern() {
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:
use tupley::prelude::*;
fn tuple_len() {
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)
use tupley::prelude::*;
fn tuple_add() {
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)));
}
fn tuple_push() {
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
:
use tupley::prelude::*;
fn tuple_as_to() {
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):
Notice
: You should enable feature len-generic
switch toolchain into nightly
#![cfg_attr(feature = "len-generic", feature(generic_const_exprs))]
use tupley::prelude::*;
#[cfg(feature = "len-generic")]
fn tuple_len_generic() {
let t = tup!(1, 2, 3);
fn eq_yes<T: TupleLenEq<3>>(_: T) {}
eq_yes(t);
fn gt_yes<T: TupleLenGt<2>>(_: T) {}
gt_yes(t);
fn ge_yes_1<T: TupleLenGe<3>>(_: T) {}
ge_yes_1(t);
fn ge_yes_2<T: TupleLenGe<2>>(_: T) {}
ge_yes_2(t);
// LEN >= 3, LEN < 4
fn range_yes<T: TupleLenRange<3, 4>>(_: T) {}
range_yes(t);
// The following will failed in compile time
//
//
// fn ge_err<T: TupleLenGe<4>>(_: T) {}
// ge_err(t);
//
//
// fn gt_err<T: TupleLenGt<4>>(_: T) {}
// gt_err(t);
//
//
// fn eq_err<T: TupleLenEq<2>>(_: T) {}
// eq_err(t);
}
More work WIP.