Skip to content

Instantly share code, notes, and snippets.

@fredpointzero
Created October 7, 2019 07:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fredpointzero/7b40e93d3e2226ca4aec00fdd1bc3e20 to your computer and use it in GitHub Desktop.
Save fredpointzero/7b40e93d3e2226ca4aec00fdd1bc3e20 to your computer and use it in GitHub Desktop.
Variadic tuples

Use cases

Variadic tuples(rust-lang/rfcs#2775)

Hash

Hash trait from std

impl<(..T), Last> Hash for (..T, Last)
where
    ..(T: Hash,),
    Last: Hash + ?Sized, {

    #[allow(non_snake_case)]
    fn hash<S: Hasher>(&self, state: &mut S) {
        let (ref tuple @ .., ref last) = *self;
        for member in tuple {
          member.hash(state);
        };
        last.hash(state);
    }
}

Merge

Merge two tuples together

trait Merge<(..R)> {
    type Value;
    fn merge(self, r: (..R)) -> Self::Value;
}
impl<(..L), (..R)> Merge<(..R)> for (..L) {
    type Value = (..L, ..R);
    fn merge(self, r: (..R)) -> Self::Value {
        (for l in self { l }, for r in r { r })
    }
}

Rev

Reverse order of tuple members

trait Rev {
    type Value;
    fn rev(self) -> Self::Value;
}
impl Rev for () {
    type Value = ();
    fn rev(self) -> Self::Value { () }
}
impl<Head, (..Tail)> Rev for (Head, ..Tail)
where
    (..Tail): Rev,
    <(..Tail) as Rev>::Value: Merge<(Head,)> {
    type Value = <<(..Tail) as Rev>::Value as Merge<(Head,)>>::Output;

    fn rev(self) -> Self::Value {
        let (h, t @ ..) = self;
        let rev_t = <(..Tail) as Rev>::rev(t);
        rev_t.merge((h,))
    }
}

Zip

Join two tuples of the same size, the result tuple will be a tuple where each of its member is a tuple with first member coming from first tuple and second member from second tuple.

trait Zip<T> {
type Out;
fn zip(self, value: T) -> Self::Out;
}

impl<(..(L, R)> Zip<(..R)> for (..L) {
    type Out = (..(L, R));

    fn zip(self, value: (..R)) -> Self::Out {
        for (l, r) in (self, value) {
            (l, r)
        }
    }
}

Split

Split a tuple into two tuples with specified result tuples

fn split<(..L), (..R)>(value: (..L, ..R)) -> ((..L), (..R)) {
    let (l @ .., r @ ..) = value;
    (l, r)
}

MegaMap

Define a structure that use a tuple of HashMap defined by generic parameters

struct MegaMap<(..(K, V))> {
  maps: (..HashMap<K, V>),
}

impl<(..(K, V))> MegaMap<(..(K, V))>
where ..(K: Hash), {
    fn get(&self, k: (..K)) -> (..Option<V>) {
        let result: (..Option<&V>) = {
            (for (ref k, map), (Key, Value) in (k, &self.maps), (K, V) {
                HashMap::<Key, Value>::get(&map, k)
            })
        };

        result
    }
}

Capacities with zero cost abstractions

Define a zero cost abstraction pattern to make sure some hypotheses are true

struct CanRead;
struct CanAdd;
struct CanWrite;
struct CanRemove;

struct Token<(..C)>;

trait Has<T> {
const VALUE: bool;
}
impl<T> Has<T> for () {
const VALUE: bool = false;
}
impl<T, Head, (..Tuple)> Has<T> for (Head, ..Tuple)
where (..Tuple): Has<T>, {
const VALUE: bool = TypeId::of::<Head>() == TypeId::of::<T>() || (..Tuple)::VALUE;
}

fn read<(..T)>(token: Token<(..T)>)
where T: Has<CanRead> {
    const_assert!(T::Value);
}

Add generalized arity tuples #2702

Hash

impl<T, Last> Hash for Tuple<T, Last>
where
    T: Hash,
    Last: Hash + ?Sized, {

    #[allow(non_snake_case)]
    fn hash<S: Hasher>(&self, state: &mut S) {
        self.elem.hash(state);
        self.tail.hash(state);
    }
}

Merge

trait Merge<T> {
    type Out;

    fn merge(self, value: T) -> Self::Out;
}

impl<T, Elem, Tail> Merge<T> for Tuple<Elem, Tail>
where Tail: Merge<Elem> {
    type Out = Tuple<T, <Tail as Merge<Elem>>::Out>;

    fn merge(self, value: T) -> Self::Out {
        Tuple::new(value, <Tail as Merge<Elem>>::merge(self.tail, self.elem))
    } 
}

Rev

trait Rev {
    type Out;

    fn rev(self) -> Self::Out;
}

impl Rev for () {
    type Out = ();

    fn rev(self) -> Self::Out { () }
}
impl<T> Rev for (T, ) {
    type Out = (T, );

    fn rev(self) -> Self::Out { self }
}

impl<L, R> Rev for (L, R) {
    type Out = (R, L);

    fn rev(self) -> Self::Out { (self.1, self.0) }
}
impl<Head, Tail> Rev for Tuple<Head, Tail> 
where 
    Tail: Rev,
    <Tail as Rev>::Out: Merge<Head> {
    type Out = <<Tail as Rev>::Out as Merge<Head>>::Out;

    fn rev(self) -> Self::Out {
        <<Tail as Rev>::Out as Merge<Head>>::merge(<Tail as Rev>::rev(self.tail), self.elem)
    }
}

Zip

trait Zip<T> {
    type Out;

    fn zip(self, other: T) -> Self::Out;
}


impl Zip<()> for () {
    type Out = ();
    fn zip(self, other: ()) -> () { () }
}
impl<LE, LT, RE, RT> Zip<Tuple<RE, RT>> for Tuple<LE, LT>
where
    LE: Zip<RT> {
    type Out = Tuple<(LE, RE), <LE as Zip<RT>>::Out>;

    fn zip(self, other: Tuple<RE, RT>) -> Self::Out {
        Tuple::new((self.elem, other.elem), <LT as Zip<RT>>::zip(self.tail, other.tail))
    }
}

Split

???

MegaMap

???

Capacities with zero cost abstractions

struct CanRead;
struct CanAdd;
struct CanWrite;
struct CanRemove;

struct Token<(..C)>;

trait Has<T> {
const VALUE: bool;
}
impl<T> Has<T> for () {
const VALUE: bool = false;
}
impl<T, Head, Tail> Has<T> for Tuple<Head, Tail>
where Tail: Has<T>, {
const VALUE: bool = TypeId::of::<Head>() == TypeId::of::<T>() || Tail::VALUE;
}

fn read<(..T)>(token: Token<(..T)>)
where T: Has<CanRead> {
    const_assert!(T::Value);
    // we are allowed to read
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment