#![deny(missing_docs)]
pub trait UnzipInto<T> {
fn unzip_into(self) -> T;
}
impl<T, U> UnzipInto<T> for U
where
T: UnzipFrom<U>,
{
fn unzip_into(self) -> T {
T::unzip_from(self)
}
}
pub trait UnzipFrom<T>
where
T: ?Sized,
{
fn unzip_from(tuple: T) -> Self;
}
macro_rules! left {
($a:tt) => { $a };
($a:tt $b:ident) => { ($a, $b) };
($a:tt $b:ident $($c:ident)*) => { left!(($a, $b) $($c)*) };
}
macro_rules! right {
($a:tt) => { $a };
($a:tt $b:ident) => { ($a, $b) };
($a:tt $b:ident $($c:ident)*) => { ($a, ($b, right!($($c)*))) };
}
macro_rules! nested {
($a:ident $b:ident $c:ident $($ident:ident)*) => {
nested!(@ $a $b $c ; $($ident)*);
};
(@ $($ident:ident)* ; $next:ident $($rest:ident)*) => {
nested!(@ $($ident)* ;);
nested!(@ $($ident)* $next ; $($rest)*);
};
(@ $($ident:ident)* ;) => {
#[allow(non_snake_case)]
impl<$($ident,)*> UnzipFrom<left!($($ident)*)> for ($($ident,)*) {
fn unzip_from(zip: left!($($ident)*)) -> Self {
let left!($($ident)*) = zip;
($($ident,)*)
}
}
#[allow(non_snake_case)]
impl<$($ident,)*> UnzipFrom<right!($($ident)*)> for ($($ident,)*) {
fn unzip_from(zip: right!($($ident)*)) -> Self {
let right!($($ident)*) = zip;
($($ident,)*)
}
}
}
}
impl<T, U> UnzipFrom<Option<T>> for Option<U>
where
U: UnzipFrom<T>,
{
fn unzip_from(tuple: Option<T>) -> Self {
tuple.map(UnzipFrom::unzip_from)
}
}
impl<T, E, U> UnzipFrom<Result<T, E>> for Result<U, E>
where
U: UnzipFrom<T>,
{
fn unzip_from(tuple: Result<T, E>) -> Self {
tuple.map(UnzipFrom::unzip_from)
}
}
impl<A> UnzipFrom<(A,)> for (A,) {
fn unzip_from(tuple: (A,)) -> Self {
tuple
}
}
impl<A, B> UnzipFrom<(A, B)> for (A, B) {
fn unzip_from(tuple: (A, B)) -> Self {
tuple
}
}
nested!(A B C D E F G H I J K L M N O P Q R S T U V W X Y Z);
#[cfg(test)]
#[allow(unused)]
mod tests {
use super::{UnzipFrom, UnzipInto};
#[test]
fn test_left_recursive_tuple() {
let (x, y, z) = ((1, 2), 3).unzip_into();
}
#[test]
fn test_right_recursive_tuple() {
let (x, y, z) = (1, (2, 3)).unzip_into();
}
#[test]
fn test_left_recursive_option() {
let zipped = Some(false).zip(Some(false)).zip(Some(false));
match zipped.unzip_into() {
Some((a, b, c)) => {}
None => {}
}
}
#[test]
fn test_left_recursive_result() {
let zipped = Ok::<_, ()>(false)
.and_then(|a| Ok((a, false)))
.and_then(|ab| Ok((ab, false)));
match zipped.unzip_into() {
Ok((a, b, c)) => {}
Err(_) => {}
}
}
}