Skip to content

Latest commit

 

History

History
246 lines (182 loc) · 4.61 KB

README.md

File metadata and controls

246 lines (182 loc) · 4.61 KB

tupley

Intro

Extension for primitive tuple (Hlist based on recursive structure).
You could use it to contain elements with different types.

Struct

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)))

Usage

  • 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.