Skip to content

Instantly share code, notes, and snippets.

@dylanede
Forked from anonymous/playground.rs
Created February 19, 2016 17:29
Show Gist options
  • Save dylanede/9d434281b366869d060c to your computer and use it in GitHub Desktop.
Save dylanede/9d434281b366869d060c to your computer and use it in GitHub Desktop.
Shared via Rust Playground
trait Merge<A, B> {
type Out;
fn merge(a: A, b: B) -> Self::Out;
}
type MergeOut<A, B> = <() as Merge<A, B>>::Out;
fn merge<A, B>(a: A, b: B) -> MergeOut<A, B> where (): Merge<A, B> {
<() as Merge<A, B>>::merge(a, b)
}
struct Unknown;
macro_rules! derive_merge_unknown {
($t:ty) => {
impl Merge<$t, Unknown> for () {
type Out = $t;
fn merge(a: $t, _: Unknown) -> $t { a }
}
impl Merge<Unknown, $t> for () {
type Out = $t;
fn merge(_: Unknown, b: $t) -> $t { b }
}
};
($t:ty; ($($params:ident),*)) => {
impl<$($params),*> Merge<$t, Unknown> for () {
type Out = $t;
fn merge(a: $t, _: Unknown) -> $t { a }
}
impl<$($params),*> Merge<Unknown, $t> for () {
type Out = $t;
fn merge(_: Unknown, b: $t) -> $t { b }
}
};
}
struct Nil;
struct Cons<A, B>(A, B);
macro_rules! hlist {
() => { Nil };
(_) => { Cons(Unknown, Nil) };
(_, $($t:tt)*) => { Cons(Unknown, hlist![$($t)*]) };
($e:expr) => { Cons($e, Nil) };
($e:expr, $($t:tt)*) => { Cons($e, hlist![$($t)*]) };
}
struct Buffer;
struct Image;
struct Set<L>(L);
impl Merge<Buffer, Buffer> for () {
type Out = Buffer;
fn merge(a: Buffer, b: Buffer) -> Buffer { Buffer }
}
derive_merge_unknown!(Buffer);
impl Merge<Image, Image> for () {
type Out = Image;
fn merge(a: Image, b: Image) -> Image { Image }
}
derive_merge_unknown!(Image);
impl<L1, L2> Merge<Set<L1>, Set<L2>> for () where (): Merge<L1, L2> {
type Out = Set<MergeOut<L1, L2>>;
fn merge(a: Set<L1>, b: Set<L2>) -> Self::Out { Set(merge(a.0, b.0)) }
}
derive_merge_unknown!(Set<L>; (L));
impl Merge<Nil, Nil> for () {
type Out = Nil;
fn merge(a: Nil, b: Nil) -> Nil { Nil }
}
derive_merge_unknown!(Nil);
impl<A, B> Merge<Cons<A, B>, Nil> for () {
type Out = Cons<A, B>;
fn merge(a: Cons<A, B>, b: Nil) -> Cons<A, B> { a }
}
impl<A, B> Merge<Nil, Cons<A, B>> for () {
type Out = Cons<A, B>;
fn merge(a: Nil, b: Cons<A, B>) -> Cons<A, B> { b }
}
impl<A, B, C, D> Merge<Cons<A, B>, Cons<C, D>> for () where (): Merge<A, C>, (): Merge<B, D> {
type Out = Cons<MergeOut<A, C>, MergeOut<B, D>>;
fn merge(a: Cons<A, B>, b: Cons<C, D>) -> Self::Out {
Cons(merge(a.0, b.0), merge(a.1, b.1))
}
}
derive_merge_unknown!(Cons<A, B>; (A, B));
fn main() {
// Set #0, Pos #1 is Buffer
let a = hlist![Set(hlist![_, Buffer])];
// Set #0, Pos #0 is Image, Set #1, Pos #0 is Buffer
let b = hlist![Set(hlist![Image]), Set(hlist![Buffer])];
// ta da!
let c: () = merge(a, b);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment