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

geo-engine / geoengine / 3676601107

pending completion
3676601107

push

github

GitHub
Merge #695

42001 of 50014 relevant lines covered (83.98%)

2.01 hits per line

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

22.35
/datatypes/src/raster/data_type.rs
1
use crate::error::{self, Error};
2
use crate::operations::image::RgbaTransmutable;
3
use crate::raster::TypedRasterConversion;
4
use crate::util::Result;
5
use gdal::raster::GdalDataType;
6
use num_traits::{AsPrimitive, Bounded, Num};
7
use serde::{Deserialize, Serialize};
8
use std::convert::TryFrom;
9

10
use super::{GridShape2D, GridShape3D};
11

12
/// A collection of required traits for a pixel type
13
pub trait Pixel:
14
    'static
15
    + Copy
16
    + std::fmt::Debug
17
    + Sync
18
    + Send
19
    + Num
20
    + Bounded
21
    + PartialOrd
22
    + AsPrimitive<u8>
23
    + AsPrimitive<i8>
24
    + AsPrimitive<u16>
25
    + AsPrimitive<i16>
26
    + AsPrimitive<u32>
27
    + AsPrimitive<i32>
28
    + AsPrimitive<u64>
29
    + AsPrimitive<i64>
30
    + AsPrimitive<f32>
31
    + AsPrimitive<f64>
32
    + AsPrimitive<Self>
33
    + FromPrimitive<u8>
34
    + FromPrimitive<i8>
35
    + FromPrimitive<u16>
36
    + FromPrimitive<i16>
37
    + FromPrimitive<u32>
38
    + FromPrimitive<i32>
39
    + FromPrimitive<u64>
40
    + FromPrimitive<i64>
41
    + FromPrimitive<f32>
42
    + FromPrimitive<f64>
43
    + FromPrimitive<Self>
44
    + StaticRasterDataType
45
    + RgbaTransmutable
46
    + TypedRasterConversion<GridShape2D>
47
    + TypedRasterConversion<GridShape3D>
48
    + SaturatingOps
49
{
50
}
51

52
pub trait FromPrimitive<T>
53
where
54
    T: Pixel,
55
{
56
    fn from_(value: T) -> Self;
57
}
58

59
impl<T, V> FromPrimitive<V> for T
60
where
61
    T: Pixel,
62
    V: Pixel + AsPrimitive<T>,
63
{
64
    fn from_(value: V) -> Self {
10✔
65
        value.as_()
10✔
66
    }
67
}
68

69
/// Saturating operations for the `Pixel` type that do not overflow.
70
pub trait SaturatingOps {
71
    fn saturating_add(self, rhs: Self) -> Self;
72
}
73

74
impl SaturatingOps for u8 {
75
    fn saturating_add(self, rhs: Self) -> Self {
1✔
76
        u8::saturating_add(self, rhs)
77
    }
78
}
79

80
impl SaturatingOps for u16 {
81
    fn saturating_add(self, rhs: Self) -> Self {
1✔
82
        u16::saturating_add(self, rhs)
83
    }
84
}
85

86
impl SaturatingOps for u32 {
87
    fn saturating_add(self, rhs: Self) -> Self {
×
88
        u32::saturating_add(self, rhs)
89
    }
90
}
91

92
impl SaturatingOps for u64 {
93
    fn saturating_add(self, rhs: Self) -> Self {
×
94
        u64::saturating_add(self, rhs)
95
    }
96
}
97

98
impl SaturatingOps for i8 {
99
    fn saturating_add(self, rhs: Self) -> Self {
×
100
        i8::saturating_add(self, rhs)
101
    }
102
}
103

104
impl SaturatingOps for i16 {
105
    fn saturating_add(self, rhs: Self) -> Self {
×
106
        i16::saturating_add(self, rhs)
107
    }
108
}
109

110
impl SaturatingOps for i32 {
111
    fn saturating_add(self, rhs: Self) -> Self {
×
112
        i32::saturating_add(self, rhs)
113
    }
114
}
115

116
impl SaturatingOps for i64 {
117
    fn saturating_add(self, rhs: Self) -> Self {
×
118
        i64::saturating_add(self, rhs)
119
    }
120
}
121

122
impl SaturatingOps for f32 {
123
    fn saturating_add(self, rhs: Self) -> Self {
×
124
        self + rhs
×
125
    }
126
}
127
impl SaturatingOps for f64 {
128
    fn saturating_add(self, rhs: Self) -> Self {
×
129
        self + rhs
×
130
    }
131
}
132

133
impl Pixel for u8 {}
134
impl Pixel for i8 {}
135
impl Pixel for u16 {}
136
impl Pixel for i16 {}
137
impl Pixel for u32 {}
138
impl Pixel for i32 {}
139
impl Pixel for u64 {}
140
impl Pixel for i64 {}
141
impl Pixel for f32 {}
142
impl Pixel for f64 {}
143

144
#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash, Deserialize, Serialize, Copy, Clone)]
145
pub enum RasterDataType {
146
    U8,
147
    U16,
148
    U32,
149
    U64,
150
    I8,
151
    I16,
152
    I32,
153
    I64,
154
    F32,
155
    F64,
156
}
157

158
impl RasterDataType {
159
    /// Returns true if the given `value` is valid for the `RasterDataType` variant,
160
    /// i.e. it can be represented by a variable of the corresponding primitive data type
161
    #[allow(clippy::float_cmp)]
162
    #[allow(clippy::cast_lossless)]
163
    pub fn is_valid(self, value: f64) -> bool {
1✔
164
        match self {
1✔
165
            RasterDataType::U8 => value as u8 as f64 == value,
1✔
166
            RasterDataType::U16 => value as u16 as f64 == value,
×
167
            RasterDataType::U32 => value as u32 as f64 == value,
×
168
            RasterDataType::U64 => value as u64 as f64 == value,
×
169
            RasterDataType::I8 => value as i8 as f64 == value,
×
170
            RasterDataType::I16 => value as i16 as f64 == value,
×
171
            RasterDataType::I32 => value as i32 as f64 == value,
×
172
            RasterDataType::I64 => value as i64 as f64 == value,
×
173
            RasterDataType::F32 => value.is_nan() || value as f32 as f64 == value,
2✔
174
            RasterDataType::F64 => true,
×
175
        }
176
    }
177

178
    pub fn from_gdal_data_type(gdal_data_type: GdalDataType) -> Result<Self> {
1✔
179
        match gdal_data_type {
1✔
180
            GdalDataType::UInt8 => Ok(Self::U8),
×
181
            GdalDataType::UInt16 => Ok(Self::U16),
×
182
            GdalDataType::Int16 => Ok(Self::I16),
1✔
183
            GdalDataType::UInt32 => Ok(Self::U32),
×
184
            GdalDataType::Int32 => Ok(Self::I32),
×
185
            GdalDataType::Float32 => Ok(Self::F32),
1✔
186
            GdalDataType::Float64 => Ok(Self::F64),
×
187
            GdalDataType::Unknown => Err(Error::GdalRasterDataTypeNotSupported),
×
188
        }
189
    }
190
}
191

192
#[derive(Debug, PartialEq, Deserialize, Serialize, Copy, Clone)]
193
pub enum TypedValue {
194
    U8(u8),
195
    U16(u16),
196
    U32(u32),
197
    U64(u64),
198
    I8(i8),
199
    I16(i16),
200
    I32(i32),
201
    I64(i64),
202
    F32(f32),
203
    F64(f64),
204
}
205

206
impl TryFrom<TypedValue> for u8 {
207
    type Error = crate::error::Error;
208

209
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
210
        if let TypedValue::U8(v) = value {
×
211
            return Ok(v);
×
212
        }
213
        Err(error::Error::InvalidTypedValueConversion)
×
214
    }
215
}
216

217
impl TryFrom<TypedValue> for u16 {
218
    type Error = crate::error::Error;
219

220
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
221
        if let TypedValue::U16(v) = value {
×
222
            return Ok(v);
×
223
        }
224
        Err(error::Error::InvalidTypedValueConversion)
×
225
    }
226
}
227

228
impl TryFrom<TypedValue> for u32 {
229
    type Error = crate::error::Error;
230

231
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
232
        if let TypedValue::U32(v) = value {
×
233
            return Ok(v);
×
234
        }
235
        Err(error::Error::InvalidTypedValueConversion)
×
236
    }
237
}
238

239
impl TryFrom<TypedValue> for u64 {
240
    type Error = crate::error::Error;
241

242
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
243
        if let TypedValue::U64(v) = value {
×
244
            return Ok(v);
×
245
        }
246
        Err(error::Error::InvalidTypedValueConversion)
×
247
    }
248
}
249

250
impl TryFrom<TypedValue> for i8 {
251
    type Error = crate::error::Error;
252

253
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
254
        if let TypedValue::I8(v) = value {
×
255
            return Ok(v);
×
256
        }
257
        Err(error::Error::InvalidTypedValueConversion)
×
258
    }
259
}
260

261
impl TryFrom<TypedValue> for i16 {
262
    type Error = crate::error::Error;
263

264
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
265
        if let TypedValue::I16(v) = value {
×
266
            return Ok(v);
×
267
        }
268
        Err(error::Error::InvalidTypedValueConversion)
×
269
    }
270
}
271

272
impl TryFrom<TypedValue> for i32 {
273
    type Error = crate::error::Error;
274

275
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
276
        if let TypedValue::I32(v) = value {
×
277
            return Ok(v);
×
278
        }
279
        Err(error::Error::InvalidTypedValueConversion)
×
280
    }
281
}
282

283
impl TryFrom<TypedValue> for i64 {
284
    type Error = crate::error::Error;
285

286
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
287
        if let TypedValue::I64(v) = value {
×
288
            return Ok(v);
×
289
        }
290
        Err(error::Error::InvalidTypedValueConversion)
×
291
    }
292
}
293

294
impl TryFrom<TypedValue> for f32 {
295
    type Error = crate::error::Error;
296

297
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
298
        if let TypedValue::F32(v) = value {
×
299
            return Ok(v);
×
300
        }
301
        Err(error::Error::InvalidTypedValueConversion)
×
302
    }
303
}
304

305
impl TryFrom<TypedValue> for f64 {
306
    type Error = crate::error::Error;
307

308
    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
×
309
        if let TypedValue::F64(v) = value {
×
310
            return Ok(v);
×
311
        }
312
        Err(error::Error::InvalidTypedValueConversion)
×
313
    }
314
}
315

316
// TODO: use a macro?
317
pub trait StaticRasterDataType: Copy + Default + 'static {
318
    const TYPE: RasterDataType;
319
}
320

321
impl StaticRasterDataType for u8 {
322
    const TYPE: RasterDataType = RasterDataType::U8;
323
}
324

325
impl StaticRasterDataType for u16 {
326
    const TYPE: RasterDataType = RasterDataType::U16;
327
}
328

329
impl StaticRasterDataType for u32 {
330
    const TYPE: RasterDataType = RasterDataType::U32;
331
}
332

333
impl StaticRasterDataType for u64 {
334
    const TYPE: RasterDataType = RasterDataType::U64;
335
}
336

337
impl StaticRasterDataType for i8 {
338
    const TYPE: RasterDataType = RasterDataType::I8;
339
}
340

341
impl StaticRasterDataType for i16 {
342
    const TYPE: RasterDataType = RasterDataType::I16;
343
}
344

345
impl StaticRasterDataType for i32 {
346
    const TYPE: RasterDataType = RasterDataType::I32;
347
}
348

349
impl StaticRasterDataType for i64 {
350
    const TYPE: RasterDataType = RasterDataType::I64;
351
}
352

353
impl StaticRasterDataType for f32 {
354
    const TYPE: RasterDataType = RasterDataType::F32;
355
}
356

357
impl StaticRasterDataType for f64 {
358
    const TYPE: RasterDataType = RasterDataType::F64;
359
}
360

361
pub trait DynamicRasterDataType {
362
    fn raster_data_type(&self) -> RasterDataType;
363
}
364

365
impl<R> DynamicRasterDataType for R
366
where
367
    R: StaticRasterDataType,
368
{
369
    fn raster_data_type(&self) -> RasterDataType {
×
370
        R::TYPE
×
371
    }
372
}
373

374
#[cfg(test)]
375
mod tests {
376
    use super::*;
377

378
    #[test]
379
    fn valid_values() {
3✔
380
        assert!(RasterDataType::U8.is_valid(0.0));
1✔
381
        assert!(RasterDataType::U8.is_valid(255.0));
2✔
382
        assert!(!RasterDataType::U8.is_valid(0.1));
2✔
383
        assert!(!RasterDataType::U8.is_valid(-1.0));
2✔
384

385
        assert!(RasterDataType::F32.is_valid(1.5));
2✔
386
        assert!(!RasterDataType::F32.is_valid(f64::MIN));
2✔
387
    }
388
}
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