1#![doc = include_str!("../README.md")]
2#![warn(
3 missing_docs,
4 missing_copy_implementations,
5 missing_debug_implementations,
6 missing_docs,
7 rust_2018_idioms
8)]
9use std::fmt::{Debug, Formatter};
10
11pub struct DynIter<'iter, V> {
22 iter: Box<dyn Iterator<Item = V> + 'iter>,
23}
24
25impl<V> Debug for DynIter<'_, V> {
26 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
27 let size_str = match self.iter.size_hint() {
28 (min, None) => format!("at least {min}",),
29 (min, Some(max)) if min == max => format!("{min}",),
30 (min, Some(max)) => format!("between {min} and {max}"),
31 };
32 write!(f, "{{ iter: [Iterator with {size_str} elements]}}")
33 }
34}
35
36impl<'iter, V> DynIter<'iter, V> {
37 pub fn new<I>(iter: I) -> Self
42 where
43 I: Iterator<Item = V> + 'iter,
44 {
45 Self {
46 iter: Box::new(iter),
47 }
48 }
49}
50
51impl<'iter, V> Iterator for DynIter<'iter, V> {
52 type Item = V;
53 fn next(&mut self) -> Option<Self::Item> {
54 self.iter.next()
55 }
56
57 fn size_hint(&self) -> (usize, Option<usize>) {
58 self.iter.size_hint()
59 }
60
61 fn count(self) -> usize
62 where
63 Self: Sized,
64 {
65 self.iter.count()
66 }
67}
68
69pub trait IntoDynIterator: Iterator {
81 #[inline]
83 fn into_dyn_iter<'iter>(self) -> DynIter<'iter, Self::Item>
84 where
85 Self: Sized + 'iter,
86 {
87 DynIter::new(self)
88 }
89}
90
91impl<T: ?Sized> IntoDynIterator for T where T: Iterator {}
92
93#[cfg(test)]
94mod tests {
95 use crate::{DynIter, IntoDynIterator as _};
96
97 #[test]
100 fn it_compiles() {
101 let iter = (0..5).skip(2).filter(|n| *n != 3);
102 let mut dyn_iter = DynIter::new(iter);
103 assert_eq!(dyn_iter.size_hint(), (0, Some(3)));
104 assert_eq!(dyn_iter.next(), Some(2));
105 assert_eq!(dyn_iter.size_hint(), (0, Some(2)));
106 assert_eq!(dyn_iter.next(), Some(4));
107 assert_eq!(dyn_iter.size_hint(), (0, Some(0)));
108 assert_eq!(dyn_iter.next(), None);
109 }
110
111 #[test]
112 fn size_hint_count() {
113 let iter = (0..5).skip(2).filter(|e| *e != 3).into_dyn_iter();
114 assert_eq!(iter.size_hint(), (0, Some(3)));
115 assert_eq!(iter.count(), 2);
116 }
117
118 mod debug {
119 use super::*;
120
121 struct SizeHintIterator {
122 min: usize,
123 max: Option<usize>,
124 }
125
126 impl Iterator for SizeHintIterator {
127 type Item = u8;
128 fn next(&mut self) -> Option<Self::Item> {
129 unimplemented!()
130 }
131 fn size_hint(&self) -> (usize, Option<usize>) {
132 (self.min, self.max)
133 }
134 }
135
136 #[test]
137 fn no_max_size_hint() {
138 let iter = SizeHintIterator { min: 2, max: None };
139 let dyn_iter = DynIter::new(iter);
140 let debug_msg = format!("{dyn_iter:?}");
141 assert_eq!("{ iter: [Iterator with at least 2 elements]}", debug_msg);
142 }
143
144 #[test]
145 fn equal_min_max_size_hint() {
146 let iter = SizeHintIterator {
147 min: 3,
148 max: Some(3),
149 };
150 let dyn_iter = DynIter::new(iter);
151 let debug_msg = format!("{dyn_iter:?}");
152 assert_eq!("{ iter: [Iterator with 3 elements]}", debug_msg);
153 }
154
155 #[test]
156 fn different_min_max_size_hint() {
157 let iter = SizeHintIterator {
158 min: 4,
159 max: Some(5),
160 };
161 let dyn_iter = DynIter::new(iter);
162 let debug_msg = format!("{dyn_iter:?}");
163 assert_eq!(
164 "{ iter: [Iterator with between 4 and 5 elements]}",
165 debug_msg
166 );
167 }
168 }
169}