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

geo-engine / geoengine / 5856046428

14 Aug 2023 01:37PM UTC coverage: 89.484% (-0.1%) from 89.596%
5856046428

push

github

web-flow
Merge pull request #848 from geo-engine/compressed-raster-cache

compress raster tile cache

475 of 475 new or added lines in 4 files covered. (100.0%)

104049 of 116277 relevant lines covered (89.48%)

62266.95 hits per line

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

81.58
/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, Pixel,
9
};
10

11
use crate::util::{ByteSize, 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,206✔
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,604✔
32
        matches!(self, GridOrEmpty::Empty(_))
1,604✔
33
    }
1,604✔
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,705,295✔
40
        match self {
6,705,295✔
41
            GridOrEmpty::Grid(g) => g.shape(),
6,703,995✔
42
            GridOrEmpty::Empty(n) => &n.shape,
1,300✔
43
        }
44
    }
6,705,295✔
45

46
    /// Transforms `self`into a `MaskedGrid`
47
    pub fn into_materialized_masked_grid(self) -> MaskedGrid<D, T> {
593✔
48
        match self {
593✔
49
            GridOrEmpty::Grid(g) => g,
192✔
50
            GridOrEmpty::Empty(n) => MaskedGrid::from(n),
401✔
51
        }
52
    }
593✔
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) {
385✔
64
        if self.is_empty() {
385✔
65
            let grid = self.clone().into_materialized_masked_grid();
357✔
66
            *self = GridOrEmpty::Grid(grid);
357✔
67
        }
357✔
68
    }
385✔
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,701,816✔
97
        self.shape_ref().axis_size()
6,701,816✔
98
    }
6,701,816✔
99

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

105
impl<D, P> ByteSize for GridOrEmpty<D, P>
106
where
107
    P: Pixel,
108
{
109
    fn heap_byte_size(&self) -> usize {
×
110
        match self {
×
111
            GridOrEmpty::Grid(g) => g.heap_byte_size(),
×
112
            GridOrEmpty::Empty(n) => n.heap_byte_size(),
×
113
        }
114
    }
×
115
}
116

117
impl<T, D, I> GridIndexAccess<Option<T>, I> for GridOrEmpty<D, T>
118
where
119
    MaskedGrid<D, T>: GridIndexAccess<Option<T>, I>,
120
    T: Copy,
121
{
122
    fn get_at_grid_index(&self, grid_index: I) -> Result<Option<T>> {
110✔
123
        match self {
110✔
124
            GridOrEmpty::Grid(g) => g.get_at_grid_index(grid_index),
106✔
125
            GridOrEmpty::Empty(_) => Ok(None), // TODO: check if index in bounds?
4✔
126
        }
127
    }
110✔
128

129
    fn get_at_grid_index_unchecked(&self, grid_index: I) -> Option<T> {
25,369,762✔
130
        match self {
25,369,762✔
131
            GridOrEmpty::Grid(g) => g.get_at_grid_index_unchecked(grid_index),
24,321,186✔
132
            GridOrEmpty::Empty(_) => None,
1,048,576✔
133
        }
134
    }
25,369,762✔
135
}
136

137
impl<D, T, I> GridBounds for GridOrEmpty<D, T>
138
where
139
    D: GridBounds<IndexArray = I> + GridSpaceToLinearSpace<IndexArray = I>,
140
    T: Clone,
141
    I: AsRef<[isize]> + Into<GridIdx<I>>,
142
{
143
    type IndexArray = I;
144

145
    fn min_index(&self) -> GridIdx<Self::IndexArray> {
4✔
146
        match self {
4✔
147
            GridOrEmpty::Grid(g) => g.min_index(),
2✔
148
            GridOrEmpty::Empty(n) => n.min_index(),
2✔
149
        }
150
    }
4✔
151

152
    fn max_index(&self) -> GridIdx<Self::IndexArray> {
4✔
153
        match self {
4✔
154
            GridOrEmpty::Grid(g) => g.max_index(),
2✔
155
            GridOrEmpty::Empty(n) => n.max_index(),
2✔
156
        }
157
    }
4✔
158
}
159

160
impl<D, T> GridShapeAccess for GridOrEmpty<D, T>
161
where
162
    D: GridSize,
163
    D::ShapeArray: Into<GridShape<D::ShapeArray>>,
164
    T: Copy,
165
{
166
    type ShapeArray = D::ShapeArray;
167

168
    fn grid_shape_array(&self) -> Self::ShapeArray {
1,389✔
169
        match self {
1,389✔
170
            GridOrEmpty::Grid(g) => g.grid_shape_array(),
1,007✔
171
            GridOrEmpty::Empty(n) => n.grid_shape_array(),
382✔
172
        }
173
    }
1,389✔
174
}
175

176
impl<D, T> From<EmptyGrid<D, T>> for GridOrEmpty<D, T>
177
where
178
    T: Clone,
179
{
180
    fn from(no_grid_array: EmptyGrid<D, T>) -> Self {
158,308✔
181
        GridOrEmpty::Empty(no_grid_array)
158,308✔
182
    }
158,308✔
183
}
184

185
impl<D, T> From<MaskedGrid<D, T>> for GridOrEmpty<D, T>
186
where
187
    T: Clone,
188
{
189
    fn from(grid: MaskedGrid<D, T>) -> Self {
1,220✔
190
        GridOrEmpty::Grid(grid)
1,220✔
191
    }
1,220✔
192
}
193

194
impl<D, T> From<Grid<D, T>> for GridOrEmpty<D, T>
195
where
196
    T: Clone,
197
    D: GridSize + std::cmp::PartialEq + Clone,
198
{
199
    fn from(grid: Grid<D, T>) -> Self {
395✔
200
        Self::from(MaskedGrid::from(grid))
395✔
201
    }
395✔
202
}
203

204
impl<D, T, I> ChangeGridBounds<I> for GridOrEmpty<D, T>
205
where
206
    I: AsRef<[isize]> + Clone,
207
    D: GridBounds<IndexArray = I> + Clone + GridSpaceToLinearSpace<IndexArray = I>,
208
    T: Copy,
209
    GridBoundingBox<I>: GridSize,
210
    GridIdx<I>: Add<Output = GridIdx<I>> + From<I>,
211
{
212
    type Output = GridOrEmpty<GridBoundingBox<I>, T>;
213

214
    fn shift_by_offset(self, offset: GridIdx<I>) -> Self::Output {
268✔
215
        match self {
268✔
216
            GridOrEmpty::Grid(g) => GridOrEmpty::Grid(g.shift_by_offset(offset)),
236✔
217
            GridOrEmpty::Empty(n) => GridOrEmpty::Empty(n.shift_by_offset(offset)),
32✔
218
        }
219
    }
268✔
220

221
    fn set_grid_bounds(self, bounds: GridBoundingBox<I>) -> Result<Self::Output> {
×
222
        match self {
×
223
            GridOrEmpty::Grid(g) => g.set_grid_bounds(bounds).map(Into::into),
×
224
            GridOrEmpty::Empty(n) => n.set_grid_bounds(bounds).map(Into::into),
×
225
        }
226
    }
×
227
}
228

229
#[cfg(test)]
230
mod tests {
231
    use crate::raster::{BoundedGrid, Grid2D, GridBoundingBox2D};
232

233
    use super::*;
234

235
    #[test]
1✔
236
    fn grid_bounds_2d_empty_grid() {
1✔
237
        let dim: GridShape2D = [3, 2].into();
1✔
238
        let raster2d: GridOrEmpty2D<u8> = EmptyGrid::new(dim).into(); // FIXME: find out why type is needed
1✔
239

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

243
        let exp_bbox = GridBoundingBox2D::new([0, 0], [2, 1]).unwrap();
1✔
244
        assert_eq!(raster2d.bounding_box(), exp_bbox);
1✔
245
    }
1✔
246

247
    #[test]
1✔
248
    fn grid_bounds_2d_grid() {
1✔
249
        let dim: GridShape2D = [3, 2].into();
1✔
250
        let data = [1, 2, 3, 4, 5, 6].into();
1✔
251
        let raster2d: GridOrEmpty2D<_> = Grid2D::new(dim, data).unwrap().into();
1✔
252

1✔
253
        assert_eq!(raster2d.min_index(), GridIdx([0, 0]));
1✔
254
        assert_eq!(raster2d.max_index(), GridIdx([2, 1]));
1✔
255

256
        let exp_bbox = GridBoundingBox2D::new([0, 0], [2, 1]).unwrap();
1✔
257
        assert_eq!(raster2d.bounding_box(), exp_bbox);
1✔
258
    }
1✔
259
}
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