Coverage Report

Created: 2026-07-13 08:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/geo-0.32.0/src/utils.rs
Line
Count
Source
1
//! Internal utility functions, types, and data structures.
2
3
use geo_types::{Coord, CoordFloat, CoordNum};
4
use num_traits::FromPrimitive;
5
6
/// Partition a mutable slice in-place so that it contains all elements for
7
/// which `predicate(e)` is `true`, followed by all elements for which
8
/// `predicate(e)` is `false`. Returns sub-slices to all predicated and
9
/// non-predicated elements, respectively.
10
///
11
/// https://github.com/llogiq/partition/blob/master/src/lib.rs
12
0
pub fn partition_slice<T, P>(data: &mut [T], predicate: P) -> (&mut [T], &mut [T])
13
0
where
14
0
    P: Fn(&T) -> bool,
15
{
16
0
    let len = data.len();
17
0
    if len == 0 {
18
0
        return (&mut [], &mut []);
19
0
    }
20
0
    let (mut l, mut r) = (0, len - 1);
21
    loop {
22
0
        while l < len && predicate(&data[l]) {
23
0
            l += 1;
24
0
        }
25
0
        while r > 0 && !predicate(&data[r]) {
26
0
            r -= 1;
27
0
        }
28
0
        if l >= r {
29
0
            return data.split_at_mut(l);
30
0
        }
31
0
        data.swap(l, r);
32
    }
33
0
}
34
35
pub enum EitherIter<I1, I2> {
36
    A(I1),
37
    B(I2),
38
}
39
40
impl<I1, I2> ExactSizeIterator for EitherIter<I1, I2>
41
where
42
    I1: ExactSizeIterator,
43
    I2: ExactSizeIterator<Item = I1::Item>,
44
{
45
    #[inline]
46
0
    fn len(&self) -> usize {
47
0
        match self {
48
0
            EitherIter::A(i1) => i1.len(),
49
0
            EitherIter::B(i2) => i2.len(),
50
        }
51
0
    }
52
}
53
54
impl<T, I1, I2> Iterator for EitherIter<I1, I2>
55
where
56
    I1: Iterator<Item = T>,
57
    I2: Iterator<Item = T>,
58
{
59
    type Item = T;
60
61
    #[inline]
62
0
    fn next(&mut self) -> Option<Self::Item> {
63
0
        match self {
64
0
            EitherIter::A(iter) => iter.next(),
65
0
            EitherIter::B(iter) => iter.next(),
66
        }
67
0
    }
68
69
    #[inline]
70
0
    fn size_hint(&self) -> (usize, Option<usize>) {
71
0
        match self {
72
0
            EitherIter::A(iter) => iter.size_hint(),
73
0
            EitherIter::B(iter) => iter.size_hint(),
74
        }
75
0
    }
76
}
77
78
// The Rust standard library has `max` for `Ord`, but not for `PartialOrd`
79
0
pub fn partial_max<T: PartialOrd>(a: T, b: T) -> T {
80
0
    if a > b { a } else { b }
81
0
}
82
83
// The Rust standard library has `min` for `Ord`, but not for `PartialOrd`
84
0
pub fn partial_min<T: PartialOrd>(a: T, b: T) -> T {
85
0
    if a < b { a } else { b }
86
0
}
87
88
use std::cmp::Ordering;
89
90
/// Compare two coordinates lexicographically: first by the
91
/// x coordinate, and break ties with the y coordinate.
92
/// Expects none of coordinates to be uncomparable (eg. nan)
93
#[inline]
94
0
pub fn lex_cmp<T: CoordNum>(p: &Coord<T>, q: &Coord<T>) -> Ordering {
95
0
    p.x.partial_cmp(&q.x)
96
0
        .unwrap()
97
0
        .then(p.y.partial_cmp(&q.y).unwrap())
98
0
}
Unexecuted instantiation: geo::utils::lex_cmp::<f64>
Unexecuted instantiation: geo::utils::lex_cmp::<_>
99
100
/// Compute index of the least point in slice. Comparison is
101
/// done using [`lex_cmp`].
102
///
103
/// Should only be called on a non-empty slice with no `nan`
104
/// coordinates.
105
0
pub fn least_index<T: CoordNum>(pts: &[Coord<T>]) -> usize {
106
0
    pts.iter()
107
0
        .enumerate()
108
0
        .min_by(|(_, p), (_, q)| lex_cmp(p, q))
Unexecuted instantiation: geo::utils::least_index::<f64>::{closure#0}
Unexecuted instantiation: geo::utils::least_index::<_>::{closure#0}
109
0
        .unwrap()
110
        .0
111
0
}
Unexecuted instantiation: geo::utils::least_index::<f64>
Unexecuted instantiation: geo::utils::least_index::<_>
112
113
/// Compute index of the lexicographically least _and_ the
114
/// greatest coordinate in one pass.
115
///
116
/// Should only be called on a non-empty slice with no `nan`
117
/// coordinates.
118
0
pub fn least_and_greatest_index<T: CoordNum>(pts: &[Coord<T>]) -> (usize, usize) {
119
0
    assert_ne!(pts.len(), 0);
120
0
    let (min, max) = pts
121
0
        .iter()
122
0
        .enumerate()
123
0
        .fold((None, None), |(min, max), (idx, p)| {
124
            (
125
0
                if let Some((midx, min)) = min {
126
0
                    if lex_cmp(p, min) == Ordering::Less {
127
0
                        Some((idx, p))
128
                    } else {
129
0
                        Some((midx, min))
130
                    }
131
                } else {
132
0
                    Some((idx, p))
133
                },
134
0
                if let Some((midx, max)) = max {
135
0
                    if lex_cmp(p, max) == Ordering::Greater {
136
0
                        Some((idx, p))
137
                    } else {
138
0
                        Some((midx, max))
139
                    }
140
                } else {
141
0
                    Some((idx, p))
142
                },
143
            )
144
0
        });
145
0
    (min.unwrap().0, max.unwrap().0)
146
0
}
147
148
/// Normalize a longitude to coordinate to ensure it's within [-180,180]
149
0
pub fn normalize_longitude<T: CoordFloat + FromPrimitive>(coord: T) -> T {
150
0
    let one_eighty = T::from(180.0f64).unwrap();
151
0
    let three_sixty = T::from(360.0f64).unwrap();
152
0
    let five_forty = T::from(540.0f64).unwrap();
153
154
0
    ((coord + five_forty) % three_sixty) - one_eighty
155
0
}
156
157
#[cfg(test)]
158
mod 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
}