• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

geo-engine / geoengine / 3929938005

pending completion
3929938005

push

github

GitHub
Merge #713

84930 of 96741 relevant lines covered (87.79%)

79640.1 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

82.57
/datatypes/src/raster/grid_or_empty.rs
1
use std::ops::Add;
2

3
use super::{
4
    empty_grid::EmptyGrid,
5
    grid_traits::{ChangeGridBounds, GridShapeAccess},
6
    masked_grid::MaskedGrid,
7
    Grid, GridBoundingBox, GridBounds, GridIdx, GridIndexAccess, GridShape, GridShape1D,
8
    GridShape2D, GridShape3D, GridSize, GridSpaceToLinearSpace,
9
};
10

11
use crate::util::Result;
12
use serde::{Deserialize, Serialize};
13

14
pub type GridOrEmpty1D<T> = GridOrEmpty<GridShape1D, T>;
15
pub type GridOrEmpty2D<T> = GridOrEmpty<GridShape2D, T>;
16
pub type GridOrEmpty3D<T> = GridOrEmpty<GridShape3D, T>;
17

18
#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)]
1,040✔
19
#[serde(rename_all = "camelCase")]
20
#[serde(tag = "type")]
21
pub enum GridOrEmpty<D, T> {
22
    Grid(MaskedGrid<D, T>),
23
    Empty(EmptyGrid<D, T>),
24
}
25

26
impl<D, T> GridOrEmpty<D, T>
27
where
28
    D: GridSize + PartialEq + Clone,
29
    T: Clone + Default,
30
{
31
    pub fn is_empty(&self) -> bool {
1,441✔
32
        matches!(self, GridOrEmpty::Empty(_))
1,441✔
33
    }
1,441✔
34

35
    pub fn is_grid(&self) -> bool {
2✔
36
        matches!(self, GridOrEmpty::Grid(_))
2✔
37
    }
2✔
38

39
    pub fn shape_ref(&self) -> &D {
6,684,221✔
40
        match self {
6,684,221✔
41
            GridOrEmpty::Grid(g) => g.shape(),
6,683,089✔
42
            GridOrEmpty::Empty(n) => &n.shape,
1,132✔
43
        }
44
    }
6,684,221✔
45

46
    /// Transforms `self`into a `MaskedGrid`
47
    pub fn into_materialized_masked_grid(self) -> MaskedGrid<D, T> {
452✔
48
        match self {
452✔
49
            GridOrEmpty::Grid(g) => g,
120✔
50
            GridOrEmpty::Empty(n) => MaskedGrid::from(n),
332✔
51
        }
52
    }
452✔
53

54
    /// Creates an `EmptyGrid` with the same shape and type.
55
    pub fn matching_empty_grid(&self) -> EmptyGrid<D, T> {
×
56
        match self {
×
57
            GridOrEmpty::Grid(g) => EmptyGrid::new(g.shape().clone()),
×
58
            GridOrEmpty::Empty(n) => n.clone(),
×
59
        }
60
    }
×
61

62
    /// Materialize the inner grid. This is a no-op if the grid is already materialized.
63
    pub fn materialize(&mut self) {
325✔
64
        if self.is_empty() {
325✔
65
            let grid = self.clone().into_materialized_masked_grid();
300✔
66
            *self = GridOrEmpty::Grid(grid);
300✔
67
        }
300✔
68
    }
325✔
69

70
    /// Returns an option of a reference to the inner grid.
71
    pub fn as_masked_grid(&self) -> Option<&MaskedGrid<D, T>> {
2✔
72
        match self {
2✔
73
            GridOrEmpty::Grid(g) => Some(g),
2✔
74
            GridOrEmpty::Empty(_) => None,
×
75
        }
76
    }
2✔
77

78
    /// Returns an option of a mutable reference to the inner grid.
79
    pub fn as_masked_grid_mut(&mut self) -> Option<&mut MaskedGrid<D, T>> {
×
80
        match self {
×
81
            GridOrEmpty::Grid(g) => Some(g),
×
82
            GridOrEmpty::Empty(_) => None,
×
83
        }
84
    }
×
85
}
86

87
impl<D, T> GridSize for GridOrEmpty<D, T>
88
where
89
    D: GridSize + GridSpaceToLinearSpace + PartialEq + Clone,
90
    T: Clone + Default,
91
{
92
    type ShapeArray = D::ShapeArray;
93

94
    const NDIM: usize = D::NDIM;
95

96
    fn axis_size(&self) -> Self::ShapeArray {
6,681,121✔
97
        self.shape_ref().axis_size()
6,681,121✔
98
    }
6,681,121✔
99

100
    fn number_of_elements(&self) -> usize {
×
101
        self.shape_ref().number_of_elements()
×
102
    }
×
103
}
104

105
impl<T, D, I> GridIndexAccess<Option<T>, I> for GridOrEmpty<D, T>
106
where
107
    MaskedGrid<D, T>: GridIndexAccess<Option<T>, I>,
108
    T: Copy,
109
{
110
    fn get_at_grid_index(&self, grid_index: I) -> Result<Option<T>> {
106✔
111
        match self {
106✔
112
            GridOrEmpty::Grid(g) => g.get_at_grid_index(grid_index),
102✔
113
            GridOrEmpty::Empty(_) => Ok(None), // TODO: check if index in bounds?
4✔
114
        }
115
    }
106✔
116

117
    fn get_at_grid_index_unchecked(&self, grid_index: I) -> Option<T> {
34,603,035✔
118
        match self {
34,603,035✔
119
            GridOrEmpty::Grid(g) => g.get_at_grid_index_unchecked(grid_index),
33,559,323✔
120
            GridOrEmpty::Empty(_) => None,
1,043,712✔
121
        }
122
    }
34,603,035✔
123
}
124

125
impl<D, T, I> GridBounds for GridOrEmpty<D, T>
126
where
127
    D: GridBounds<IndexArray = I> + GridSpaceToLinearSpace<IndexArray = I>,
128
    T: Clone,
129
    I: AsRef<[isize]> + Into<GridIdx<I>>,
130
{
131
    type IndexArray = I;
132

133
    fn min_index(&self) -> GridIdx<Self::IndexArray> {
4✔
134
        match self {
4✔
135
            GridOrEmpty::Grid(g) => g.min_index(),
2✔
136
            GridOrEmpty::Empty(n) => n.min_index(),
2✔
137
        }
138
    }
4✔
139

140
    fn max_index(&self) -> GridIdx<Self::IndexArray> {
4✔
141
        match self {
4✔
142
            GridOrEmpty::Grid(g) => g.max_index(),
2✔
143
            GridOrEmpty::Empty(n) => n.max_index(),
2✔
144
        }
145
    }
4✔
146
}
147

148
impl<D, T> GridShapeAccess for GridOrEmpty<D, T>
149
where
150
    D: GridSize,
151
    D::ShapeArray: Into<GridShape<D::ShapeArray>>,
152
    T: Copy,
153
{
154
    type ShapeArray = D::ShapeArray;
155

156
    fn grid_shape_array(&self) -> Self::ShapeArray {
1,242✔
157
        match self {
1,242✔
158
            GridOrEmpty::Grid(g) => g.grid_shape_array(),
962✔
159
            GridOrEmpty::Empty(n) => n.grid_shape_array(),
280✔
160
        }
161
    }
1,242✔
162
}
163

164
impl<D, T> From<EmptyGrid<D, T>> for GridOrEmpty<D, T>
165
where
166
    T: Clone,
167
{
168
    fn from(no_grid_array: EmptyGrid<D, T>) -> Self {
155,109✔
169
        GridOrEmpty::Empty(no_grid_array)
155,109✔
170
    }
155,109✔
171
}
172

173
impl<D, T> From<MaskedGrid<D, T>> for GridOrEmpty<D, T>
174
where
175
    T: Clone,
176
{
177
    fn from(grid: MaskedGrid<D, T>) -> Self {
1,034✔
178
        GridOrEmpty::Grid(grid)
1,034✔
179
    }
1,034✔
180
}
181

182
impl<D, T> From<Grid<D, T>> for GridOrEmpty<D, T>
183
where
184
    T: Clone,
185
    D: GridSize + std::cmp::PartialEq + Clone,
186
{
187
    fn from(grid: Grid<D, T>) -> Self {
340✔
188
        Self::from(MaskedGrid::from(grid))
340✔
189
    }
340✔
190
}
191

192
impl<D, T, I> ChangeGridBounds<I> for GridOrEmpty<D, T>
193
where
194
    I: AsRef<[isize]> + Clone,
195
    D: GridBounds<IndexArray = I> + Clone + GridSpaceToLinearSpace<IndexArray = I>,
196
    T: Copy,
197
    GridBoundingBox<I>: GridSize,
198
    GridIdx<I>: Add<Output = GridIdx<I>> + From<I>,
199
{
200
    type Output = GridOrEmpty<GridBoundingBox<I>, T>;
201

202
    fn shift_by_offset(self, offset: GridIdx<I>) -> Self::Output {
178✔
203
        match self {
178✔
204
            GridOrEmpty::Grid(g) => GridOrEmpty::Grid(g.shift_by_offset(offset)),
162✔
205
            GridOrEmpty::Empty(n) => GridOrEmpty::Empty(n.shift_by_offset(offset)),
16✔
206
        }
207
    }
178✔
208

209
    fn set_grid_bounds(self, bounds: GridBoundingBox<I>) -> Result<Self::Output> {
×
210
        match self {
×
211
            GridOrEmpty::Grid(g) => g.set_grid_bounds(bounds).map(Into::into),
×
212
            GridOrEmpty::Empty(n) => n.set_grid_bounds(bounds).map(Into::into),
×
213
        }
214
    }
×
215
}
216

217
#[cfg(test)]
218
mod tests {
219
    use crate::raster::{BoundedGrid, Grid2D, GridBoundingBox2D};
220

221
    use super::*;
222

223
    #[test]
1✔
224
    fn grid_bounds_2d_empty_grid() {
1✔
225
        let dim: GridShape2D = [3, 2].into();
1✔
226
        let raster2d: GridOrEmpty2D<u8> = EmptyGrid::new(dim).into(); // FIXME: find out why type is needed
1✔
227

1✔
228
        assert_eq!(raster2d.min_index(), GridIdx([0, 0]));
1✔
229
        assert_eq!(raster2d.max_index(), GridIdx([2, 1]));
1✔
230

231
        let exp_bbox = GridBoundingBox2D::new([0, 0], [2, 1]).unwrap();
1✔
232
        assert_eq!(raster2d.bounding_box(), exp_bbox);
1✔
233
    }
1✔
234

235
    #[test]
1✔
236
    fn grid_bounds_2d_grid() {
1✔
237
        let dim: GridShape2D = [3, 2].into();
1✔
238
        let data = [1, 2, 3, 4, 5, 6].into();
1✔
239
        let raster2d: GridOrEmpty2D<_> = Grid2D::new(dim, data).unwrap().into();
1✔
240

1✔
241
        assert_eq!(raster2d.min_index(), GridIdx([0, 0]));
1✔
242
        assert_eq!(raster2d.max_index(), GridIdx([2, 1]));
1✔
243

244
        let exp_bbox = GridBoundingBox2D::new([0, 0], [2, 1]).unwrap();
1✔
245
        assert_eq!(raster2d.bounding_box(), exp_bbox);
1✔
246
    }
1✔
247
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc