Skip to content

Commit

Permalink
Add trait to flatten a heterogenous list of heterogenous lists
Browse files Browse the repository at this point in the history
  • Loading branch information
tuguzT committed Jun 18, 2023
1 parent 668b60c commit 22f87be
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 1 deletion.
6 changes: 5 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,18 @@ where
Tail: HList,
{
const LEN: usize = Tail::LEN + 1;

fn is_empty(&self) -> bool {
false
}
}

mod sealed {
pub trait Sealed {}

impl Sealed for crate::Nil {}

impl<Head, Tail> Sealed for crate::Cons<Head, Tail> {}
impl<Head, Tail> Sealed for crate::Cons<Head, Tail> where Tail: Sealed {}
}

/// Macro creating heterogenous list values from list of expressions.
Expand Down
70 changes: 70 additions & 0 deletions src/ops/flatten.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use crate::{Cons, HList, Nil};

use super::Extend;

/// Flattens one level of nesting in a heterogenous list of heterogenous lists.
///
/// This is useful when you have a heterogenous list of heterogenous lists
/// and you want to remove one level of indirection.
pub trait Flatten: HList {
/// Flattened heterogenous list.
type Output: HList;

/// Flattens a heterogenous list of heterogenous lists, removing one level of indirection.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// use hlist2::{hlist, ops::Flatten};
///
/// let data = hlist![hlist![1, 2.0, true, "hello world"], hlist![5, 6.0]];
/// let flattened = data.flatten();
/// assert_eq!(flattened, hlist![1, 2.0, true, "hello world", 5, 6.0]);
/// ```
///
/// Flattening only removes one level of nesting at a time:
///
/// ```
/// use hlist2::{hlist, ops::Flatten};
///
/// let d3 = hlist![
/// hlist![hlist![1, 2], hlist![3, 4]],
/// hlist![hlist![5, 6], hlist![7, 8]],
/// ];
///
/// let d2 = d3.flatten();
/// assert_eq!(d2, hlist![hlist![1, 2], hlist![3, 4], hlist![5, 6], hlist![7, 8]]);
///
/// let d1 = d3.flatten().flatten();
/// assert_eq!(d1, hlist![1, 2, 3, 4, 5, 6, 7, 8]);
/// ```
///
/// Here we see that `flatten()` does not perform a “deep” flatten. Instead, only one level of nesting is removed.
/// That is, if you `flatten()` a three-dimensional array, the result will be two-dimensional and not one-dimensional.
/// To get a one-dimensional structure, you have to `flatten()` again.
fn flatten(self) -> Self::Output;
}

impl Flatten for Nil {
type Output = Self;

fn flatten(self) -> Self::Output {
self
}
}

impl<Head, Tail> Flatten for Cons<Head, Tail>
where
Head: Extend,
Tail: Flatten,
{
type Output = Head::Output<Tail::Output>;

fn flatten(self) -> Self::Output {
let Cons(head, tail) = self;
let tail = tail.flatten();
head.extend(tail)
}
}
2 changes: 2 additions & 0 deletions src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub use self::{
append::Append,
extend::Extend,
flatten::Flatten,
fold::{Fold, FoldFn, Folder, RFold},
get::Get,
index::{Here, There},
Expand All @@ -19,6 +20,7 @@ pub use self::{

mod append;
mod extend;
mod flatten;
mod fold;
mod get;
mod index;
Expand Down

0 comments on commit 22f87be

Please sign in to comment.