-
-
Save dylanede/9d434281b366869d060c to your computer and use it in GitHub Desktop.
Shared via Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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