diff --git a/src/lib.rs b/src/lib.rs index 27022c9..37055e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -143,6 +143,10 @@ where Tail: HList, { const LEN: usize = Tail::LEN + 1; + + fn is_empty(&self) -> bool { + false + } } mod sealed { @@ -150,7 +154,7 @@ mod sealed { impl Sealed for crate::Nil {} - impl Sealed for crate::Cons {} + impl Sealed for crate::Cons where Tail: Sealed {} } /// Macro creating heterogenous list values from list of expressions. diff --git a/src/ops/flatten.rs b/src/ops/flatten.rs new file mode 100644 index 0000000..779c749 --- /dev/null +++ b/src/ops/flatten.rs @@ -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 Flatten for Cons +where + Head: Extend, + Tail: Flatten, +{ + type Output = Head::Output; + + fn flatten(self) -> Self::Output { + let Cons(head, tail) = self; + let tail = tail.flatten(); + head.extend(tail) + } +} diff --git a/src/ops/mod.rs b/src/ops/mod.rs index 2f40909..330bbf6 100644 --- a/src/ops/mod.rs +++ b/src/ops/mod.rs @@ -3,6 +3,7 @@ pub use self::{ append::Append, extend::Extend, + flatten::Flatten, fold::{Fold, FoldFn, Folder, RFold}, get::Get, index::{Here, There}, @@ -19,6 +20,7 @@ pub use self::{ mod append; mod extend; +mod flatten; mod fold; mod get; mod index;