rspl/streams/
infinite_lists.rs1use super::Stream;
4
5use alloc::boxed::Box;
6
7type Lazy<'a, T> = dyn FnOnce() -> T + 'a;
9
10pub enum InfiniteList<'a, X: 'a> {
12 Cons(X, Box<Lazy<'a, InfiniteList<'a, X>>>),
14}
15
16impl<'a, X> InfiniteList<'a, X> {
17 #[inline]
19 pub fn cons<T>(x: X, lazy_inflist: T) -> Self
20 where
21 T: FnOnce() -> Self + 'a,
22 {
23 InfiniteList::Cons(x, Box::new(lazy_inflist))
24 }
25}
26
27impl<'a, X> InfiniteList<'a, X> {
28 pub fn constant(x: X) -> Self
39 where
40 X: Copy,
41 {
42 Self::Cons(x, Box::new(move || Self::constant(x)))
43 }
44}
45
46impl<'a, X> Stream<X> for InfiniteList<'a, X> {
47 fn head(&self) -> &X {
49 match self {
50 Self::Cons(head, _) => head,
51 }
52 }
53
54 fn tail(self) -> Self {
56 match self {
57 Self::Cons(_, tail) => tail(),
58 }
59 }
60}
61
62#[cfg(test)]
63mod tests {
64 use super::*;
65
66 use crate::assert_head_eq;
67 use crate::assert_tail_starts_with;
68
69 #[test]
70 fn test_cons() {
71 assert!(matches!(
72 InfiniteList::cons((), || InfiniteList::constant(())),
73 InfiniteList::Cons(_, _)
74 ));
75 }
76
77 #[test]
78 fn test_constant() {
79 const X: bool = true;
80
81 let mut xs = InfiniteList::constant(X);
82 assert_head_eq!(xs, X);
83 assert_tail_starts_with!(xs, [X, X]);
84 }
85
86 #[test]
87 fn test_head() {
88 let inflist = InfiniteList::cons(true, || InfiniteList::constant(false));
89 assert!(inflist.head());
90 }
91
92 #[test]
93 fn test_tail() {
94 let inflist = InfiniteList::cons(false, || {
95 InfiniteList::cons(true, || InfiniteList::constant(true))
96 });
97 assert!(inflist.tail().head());
98 }
99}