Coverage Report

Created: 2025-11-16 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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}>>::new
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::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}>>::next
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::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>::next
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::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
}