/rust/registry/src/index.crates.io-1949cf8c6b5b557f/split-iter-0.1.0/src/lib.rs
Line | Count | Source |
1 | | //! Provides the trait `Splittable`, which allows you to split an iterator |
2 | | //! according to a `predicate`. |
3 | | //! |
4 | | //! # Example |
5 | | //! |
6 | | //! ``` |
7 | | //! use split_iter::Splittable; |
8 | | //! |
9 | | //! fn main() { |
10 | | //! let (odd, even) = (1..10).split(|v| v % 2 == 0); |
11 | | //! |
12 | | //! assert_eq!(odd.collect::<Vec<_>>(), [1,3,5,7,9]); |
13 | | //! assert_eq!(even.collect::<Vec<_>>(), [2,4,6,8]); |
14 | | //! } |
15 | | //! ``` |
16 | | |
17 | | |
18 | | use std::rc::Rc; |
19 | | use std::collections::VecDeque; |
20 | | use std::cell::RefCell; |
21 | | use std::fmt::Debug; |
22 | | use std::fmt::Formatter; |
23 | | use std::fmt::Error as FmtError; |
24 | | |
25 | | |
26 | | /// Shared inner state for two `Split`s. |
27 | | struct SharedSplitState<I, P> where |
28 | | I: Iterator, |
29 | | P: FnMut(&I::Item) -> bool |
30 | | { |
31 | | /// Inner iterator. |
32 | | iter: I, |
33 | | /// Predicate that chooses whether an item |
34 | | /// goes left (`false`) or right (`true`). |
35 | | predicate: P, |
36 | | /// Cache that saves items that have been skipped by one `Split`. |
37 | | /// They will be returned next for the other `Split`. |
38 | | cache: VecDeque<I::Item>, |
39 | | /// Is the cache currently saving items for the left or for the right split? |
40 | | is_right_cached: bool, |
41 | | } |
42 | | |
43 | | impl<I, P> SharedSplitState<I, P> where |
44 | | I: Iterator, |
45 | | P: FnMut(&I::Item) -> bool |
46 | | { |
47 | | /// Creates shared inner state for two `Split`s. |
48 | 0 | fn new(iter: I, predicate: P) -> SharedSplitState<I, P> { |
49 | 0 | SharedSplitState { |
50 | 0 | iter: iter, |
51 | 0 | predicate: predicate, |
52 | 0 | cache: VecDeque::new(), |
53 | 0 | is_right_cached: false, |
54 | 0 | } |
55 | 0 | } Unexecuted instantiation: <split_iter::SharedSplitState<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#1}>>::newUnexecuted instantiation: <split_iter::SharedSplitState<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#1}>>::new |
56 | | |
57 | | /// Returns next item for the given `Split`. |
58 | 0 | fn next(&mut self, is_right: bool) -> Option<I::Item> { |
59 | | // Use cache for correct side |
60 | 0 | if is_right == self.is_right_cached { |
61 | 0 | if let Some(next) = self.cache.pop_front() { |
62 | 0 | return Some(next); |
63 | 0 | } |
64 | 0 | } |
65 | | |
66 | | // From inner iterator |
67 | 0 | while let Some(next) = self.iter.next() { |
68 | 0 | if (self.predicate)(&next) == is_right { |
69 | 0 | return Some(next); |
70 | 0 | } else { |
71 | 0 | // Fill cache with elements for opposite iterator |
72 | 0 | self.is_right_cached = !is_right; |
73 | 0 | self.cache.push_back(next); |
74 | 0 | } |
75 | | } |
76 | | |
77 | | // No element found |
78 | 0 | None |
79 | 0 | } Unexecuted instantiation: <split_iter::SharedSplitState<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#1}>>::nextUnexecuted instantiation: <split_iter::SharedSplitState<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#1}>>::next |
80 | | } |
81 | | |
82 | | |
83 | | /// One of a pair of iterators. One returns the items for which the predicate |
84 | | /// returns `false`, the other one returns the items for which the predicate |
85 | | /// returns `true`. |
86 | | #[must_use = "iterator adaptors are lazy and do nothing unless consumed"] |
87 | | pub struct Split<I, P> where |
88 | | I: Iterator, |
89 | | P: FnMut(&I::Item) -> bool |
90 | | { |
91 | | /// Shared state with the opposite iterator. |
92 | | shared: Rc<RefCell<SharedSplitState<I, P>>>, |
93 | | /// Is the iterator the right one or the left one? |
94 | | is_right: bool, |
95 | | } |
96 | | |
97 | | impl<I, P> Iterator for Split<I, P> where |
98 | | I: Iterator, |
99 | | P: FnMut(&I::Item) -> bool |
100 | | { |
101 | | type Item = I::Item; |
102 | | |
103 | 0 | fn next(&mut self) -> Option<I::Item> { |
104 | 0 | self.shared.borrow_mut().next(self.is_right) |
105 | 0 | } Unexecuted instantiation: <split_iter::Split<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#1}> as core::iter::traits::iterator::Iterator>::nextUnexecuted instantiation: <split_iter::Split<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#1}> as core::iter::traits::iterator::Iterator>::next |
106 | | } |
107 | | |
108 | | impl<I, P> Debug for Split<I, P> where |
109 | | I: Iterator + Debug, |
110 | | P: FnMut(&I::Item) -> bool |
111 | | { |
112 | | fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> { |
113 | | fmt.debug_struct("Split") |
114 | | .field("iter", &self.shared.borrow().iter) |
115 | | .finish() |
116 | | } |
117 | | } |
118 | | |
119 | | |
120 | | /// Provides an iterator adaptor method that splits an iterator into two |
121 | | /// iterators according to a predicate. |
122 | | pub trait Splittable<I> where |
123 | | I: Iterator |
124 | | { |
125 | | /// Splits the iterator. The left iterator iterates over all items for which |
126 | | /// the `predicate` returns `false`. The right iterator returns all items |
127 | | /// for which the `predicate` returns `true`. |
128 | | fn split<P>(self, predicate: P) -> (Split<I, P>, Split<I, P>) |
129 | | where P: FnMut(&I::Item) -> bool; |
130 | | } |
131 | | |
132 | | impl<I> Splittable<I> for I where |
133 | | I: Iterator |
134 | | { |
135 | 0 | fn split<P>(self, predicate: P) -> (Split<I, P>, Split<I, P>) |
136 | 0 | where P: FnMut(&I::Item) -> bool |
137 | | { |
138 | 0 | let shared = Rc::new( |
139 | 0 | RefCell::new( |
140 | 0 | SharedSplitState::new(self, predicate) |
141 | | ) |
142 | | ); |
143 | | |
144 | 0 | let left = Split { |
145 | 0 | shared: shared.clone(), |
146 | 0 | is_right: false, |
147 | 0 | }; |
148 | | |
149 | 0 | let right = Split { |
150 | 0 | shared: shared, |
151 | 0 | is_right: true, |
152 | 0 | }; |
153 | | |
154 | 0 | (left, right) |
155 | 0 | } Unexecuted instantiation: <core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#0}> as split_iter::Splittable<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>>>::split::<<ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::security::Authorization> as ztunnel::xds::client::RawHandler>::handle::{closure#1}>Unexecuted instantiation: <core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#0}> as split_iter::Splittable<core::iter::adapters::map::Map<core::slice::iter::Iter<ztunnel::xds::types::service::discovery::v3::Resource>, <ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#0}>>>::split::<<ztunnel::xds::client::HandlerWrapper<ztunnel::xds::types::istio::workload::Address> as ztunnel::xds::client::RawHandler>::handle::{closure#1}> |
156 | | } |
157 | | |
158 | | |
159 | | #[cfg(test)] |
160 | | mod tests { |
161 | | use super::Splittable; |
162 | | |
163 | | #[test] |
164 | | fn it_works() { |
165 | | let (odd, even) = (1..10).split(|v| v % 2 == 0); |
166 | | assert_eq!(odd.collect::<Vec<_>>(), [1,3,5,7,9]); |
167 | | assert_eq!(even.collect::<Vec<_>>(), [2,4,6,8]); |
168 | | |
169 | | let (low, high) = (1..20).split(|v| v >= &10); |
170 | | assert_eq!(high.collect::<Vec<_>>(), (10..20).collect::<Vec<_>>()); |
171 | | assert_eq!(low.collect::<Vec<_>>(), (1..10).collect::<Vec<_>>()); |
172 | | } |
173 | | } |