1use geo_types::{Coord, CoordFloat, CoordNum};
4use num_traits::FromPrimitive;
5
6pub fn partition_slice<T, P>(data: &mut [T], predicate: P) -> (&mut [T], &mut [T])
13where
14 P: Fn(&T) -> bool,
15{
16 let len = data.len();
17 if len == 0 {
18 return (&mut [], &mut []);
19 }
20 let (mut l, mut r) = (0, len - 1);
21 loop {
22 while l < len && predicate(&data[l]) {
23 l += 1;
24 }
25 while r > 0 && !predicate(&data[r]) {
26 r -= 1;
27 }
28 if l >= r {
29 return data.split_at_mut(l);
30 }
31 data.swap(l, r);
32 }
33}
34
35pub enum EitherIter<I1, I2> {
36 A(I1),
37 B(I2),
38}
39
40impl<I1, I2> ExactSizeIterator for EitherIter<I1, I2>
41where
42 I1: ExactSizeIterator,
43 I2: ExactSizeIterator<Item = I1::Item>,
44{
45 #[inline]
46 fn len(&self) -> usize {
47 match self {
48 EitherIter::A(i1) => i1.len(),
49 EitherIter::B(i2) => i2.len(),
50 }
51 }
52}
53
54impl<T, I1, I2> Iterator for EitherIter<I1, I2>
55where
56 I1: Iterator<Item = T>,
57 I2: Iterator<Item = T>,
58{
59 type Item = T;
60
61 #[inline]
62 fn next(&mut self) -> Option<Self::Item> {
63 match self {
64 EitherIter::A(iter) => iter.next(),
65 EitherIter::B(iter) => iter.next(),
66 }
67 }
68
69 #[inline]
70 fn size_hint(&self) -> (usize, Option<usize>) {
71 match self {
72 EitherIter::A(iter) => iter.size_hint(),
73 EitherIter::B(iter) => iter.size_hint(),
74 }
75 }
76}
77
78pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
80 if a > b { a } else { b }
81}
82
83pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
85 if a < b { a } else { b }
86}
87
88use std::cmp::Ordering;
89
90#[inline]
94pub fn lex_cmp<T: CoordNum>(p: &Coord<T>, q: &Coord<T>) -> Ordering {
95 p.x.partial_cmp(&q.x)
96 .unwrap()
97 .then(p.y.partial_cmp(&q.y).unwrap())
98}
99
100pub fn least_index<T: CoordNum>(pts: &[Coord<T>]) -> usize {
106 pts.iter()
107 .enumerate()
108 .min_by(|(_, p), (_, q)| lex_cmp(p, q))
109 .unwrap()
110 .0
111}
112
113pub fn least_and_greatest_index<T: CoordNum>(pts: &[Coord<T>]) -> (usize, usize) {
119 assert_ne!(pts.len(), 0);
120 let (min, max) = pts
121 .iter()
122 .enumerate()
123 .fold((None, None), |(min, max), (idx, p)| {
124 (
125 if let Some((midx, min)) = min {
126 if lex_cmp(p, min) == Ordering::Less {
127 Some((idx, p))
128 } else {
129 Some((midx, min))
130 }
131 } else {
132 Some((idx, p))
133 },
134 if let Some((midx, max)) = max {
135 if lex_cmp(p, max) == Ordering::Greater {
136 Some((idx, p))
137 } else {
138 Some((midx, max))
139 }
140 } else {
141 Some((idx, p))
142 },
143 )
144 });
145 (min.unwrap().0, max.unwrap().0)
146}
147
148pub fn normalize_longitude<T: CoordFloat + FromPrimitive>(coord: T) -> T {
150 let one_eighty = T::from(180.0f64).unwrap();
151 let three_sixty = T::from(360.0f64).unwrap();
152 let five_forty = T::from(540.0f64).unwrap();
153
154 ((coord + five_forty) % three_sixty) - one_eighty
155}
156
157#[cfg(test)]
158mod test {
159 use super::{partial_max, partial_min};
160
161 #[test]
162 fn test_partial_max() {
163 assert_eq!(5, partial_max(5, 4));
164 assert_eq!(5, partial_max(5, 5));
165 }
166
167 #[test]
168 fn test_partial_min() {
169 assert_eq!(4, partial_min(5, 4));
170 assert_eq!(4, partial_min(4, 4));
171 }
172}