use super::Stream;
use alloc::boxed::Box;
type Lazy<'a, T> = dyn FnOnce() -> T + 'a;
pub enum InfiniteList<'a, X: 'a> {
Cons(X, Box<Lazy<'a, InfiniteList<'a, X>>>),
}
impl<'a, X> InfiniteList<'a, X> {
#[inline]
pub fn cons<T>(x: X, lazy_inflist: T) -> Self
where
T: FnOnce() -> Self + 'a,
{
InfiniteList::Cons(x, Box::new(lazy_inflist))
}
}
impl<X> InfiniteList<'_, X> {
pub fn constant(x: X) -> Self
where
X: Copy,
{
Self::Cons(x, Box::new(move || Self::constant(x)))
}
}
impl<X> Stream<X> for InfiniteList<'_, X> {
fn head(&self) -> &X {
match self {
Self::Cons(head, _) => head,
}
}
fn tail(self) -> Self {
match self {
Self::Cons(_, tail) => tail(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::assert_head_eq;
use crate::assert_tail_starts_with;
#[test]
fn test_cons() {
assert!(matches!(
InfiniteList::cons((), || InfiniteList::constant(())),
InfiniteList::Cons((), _)
));
}
#[test]
fn test_constant() {
const X: bool = true;
let mut xs = InfiniteList::constant(X);
assert_head_eq!(xs, X);
assert_tail_starts_with!(xs, [X, X]);
}
#[test]
fn test_head() {
let inflist = InfiniteList::cons(true, || InfiniteList::constant(false));
assert!(inflist.head());
}
#[test]
fn test_tail() {
let inflist = InfiniteList::cons(false, || {
InfiniteList::cons(true, || InfiniteList::constant(true))
});
assert!(inflist.tail().head());
}
}