• 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

80.56
/datatypes/src/primitives/feature_data.rs
1
use crate::error;
2
use crate::primitives::TimeInstance;
3
use crate::util::Result;
4
use arrow::bitmap::Bitmap;
5
use gdal::vector::OGRFieldType;
6
use num_traits::AsPrimitive;
7
use serde::{Deserialize, Serialize};
8
use serde_json::Value;
9
use snafu::ensure;
10
use std::convert::TryFrom;
11
use std::str;
12
use std::{marker::PhantomData, slice};
13

14
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize)]
15,713✔
15
#[serde(rename_all = "camelCase")]
16
pub enum FeatureDataType {
17
    Category,
18
    Int,
19
    Float,
20
    Text,
21
    Bool,
22
    DateTime,
23
}
24

25
impl FeatureDataType {
26
    pub fn try_from_ogr_field_type_code(code: u32) -> Result<Self> {
×
27
        Ok(match code {
×
28
            OGRFieldType::OFTInteger | OGRFieldType::OFTInteger64 => Self::Int,
×
29
            OGRFieldType::OFTReal => Self::Float,
×
30
            OGRFieldType::OFTString => Self::Text,
×
31
            OGRFieldType::OFTBinary => Self::Bool,
×
32
            OGRFieldType::OFTDateTime | OGRFieldType::OFTDate => Self::DateTime,
×
33
            _ => return Err(error::Error::NoMatchingFeatureDataTypeForOgrFieldType),
×
34
        })
35
    }
×
36

37
    pub fn is_numeric(self) -> bool {
31✔
38
        matches!(self, Self::Int | Self::Float)
31✔
39
    }
31✔
40
}
41

42
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
223✔
43
pub enum FeatureData {
44
    Category(Vec<u8>), // TODO: add names to categories
45
    NullableCategory(Vec<Option<u8>>),
46
    Int(Vec<i64>),
47
    NullableInt(Vec<Option<i64>>),
48
    Float(Vec<f64>),
49
    NullableFloat(Vec<Option<f64>>),
50
    Text(Vec<String>),
51
    NullableText(Vec<Option<String>>),
52
    Bool(Vec<bool>),
53
    NullableBool(Vec<Option<bool>>),
54
    DateTime(Vec<TimeInstance>),
55
    NullableDateTime(Vec<Option<TimeInstance>>),
56
}
57

58
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
14✔
59
pub enum FeatureDataValue {
60
    Category(u8),
61
    NullableCategory(Option<u8>),
62
    Int(i64),
63
    NullableInt(Option<i64>),
64
    Float(f64),
65
    NullableFloat(Option<f64>),
66
    Text(String),
67
    NullableText(Option<String>),
68
    Bool(bool),
69
    NullableBool(Option<bool>),
70
    DateTime(TimeInstance),
71
    NullableDateTime(Option<TimeInstance>),
72
}
73

74
#[derive(Clone, Debug, PartialEq)]
2✔
75
pub enum FeatureDataRef<'f> {
76
    Category(CategoryDataRef<'f>),
77
    Int(IntDataRef<'f>),
78
    Float(FloatDataRef<'f>),
79
    Text(TextDataRef<'f>),
80
    Bool(BoolDataRef<'f>),
81
    DateTime(DateTimeDataRef<'f>),
82
}
83

84
impl<'f> FeatureDataRef<'f> {
85
    /// Computes JSON value lists for data elements
86
    pub fn json_values(&self) -> Box<dyn Iterator<Item = serde_json::Value> + '_> {
4✔
87
        match self {
4✔
88
            FeatureDataRef::Text(data_ref) => data_ref.json_values(),
1✔
89
            FeatureDataRef::Float(data_ref) => data_ref.json_values(),
1✔
90
            FeatureDataRef::Int(data_ref) => data_ref.json_values(),
2✔
91
            FeatureDataRef::Category(data_ref) => data_ref.json_values(),
×
92
            FeatureDataRef::Bool(data_ref) => data_ref.json_values(),
×
93
            FeatureDataRef::DateTime(data_ref) => data_ref.json_values(),
×
94
        }
95
    }
4✔
96

97
    /// Computes a vector of null flags.
98
    pub fn nulls(&self) -> Vec<bool> {
1✔
99
        match self {
1✔
100
            FeatureDataRef::Text(data_ref) => data_ref.nulls(),
1✔
101
            FeatureDataRef::Float(data_ref) => data_ref.nulls(),
×
102
            FeatureDataRef::Int(data_ref) => data_ref.nulls(),
×
103
            FeatureDataRef::Category(data_ref) => data_ref.nulls(),
×
104
            FeatureDataRef::Bool(data_ref) => data_ref.nulls(),
×
105
            FeatureDataRef::DateTime(data_ref) => data_ref.nulls(),
×
106
        }
107
    }
1✔
108

109
    /// Is any of the data elements null?
110
    pub fn has_nulls(&self) -> bool {
4✔
111
        match self {
4✔
112
            FeatureDataRef::Text(data_ref) => data_ref.has_nulls(),
2✔
113
            FeatureDataRef::Float(data_ref) => data_ref.has_nulls(),
×
114
            FeatureDataRef::Int(data_ref) => data_ref.has_nulls(),
2✔
115
            FeatureDataRef::Category(data_ref) => data_ref.has_nulls(),
×
116
            FeatureDataRef::Bool(data_ref) => data_ref.has_nulls(),
×
117
            FeatureDataRef::DateTime(data_ref) => data_ref.has_nulls(),
×
118
        }
119
    }
4✔
120

121
    /// Get the `FeatureDataValue` value at position `i`
122
    pub fn get_unchecked(&self, i: usize) -> FeatureDataValue {
59✔
123
        match self {
59✔
124
            FeatureDataRef::Text(data_ref) => data_ref.get_unchecked(i),
19✔
125
            FeatureDataRef::Float(data_ref) => data_ref.get_unchecked(i),
10✔
126
            FeatureDataRef::Int(data_ref) => data_ref.get_unchecked(i),
30✔
127
            FeatureDataRef::Category(data_ref) => data_ref.get_unchecked(i),
×
128
            FeatureDataRef::Bool(data_ref) => data_ref.get_unchecked(i),
×
129
            FeatureDataRef::DateTime(data_ref) => data_ref.get_unchecked(i),
×
130
        }
131
    }
59✔
132

133
    /// Creates an iterator over all values as string
134
    /// Null-values are empty strings.
135
    pub fn strings_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
56✔
136
        match self {
56✔
137
            FeatureDataRef::Text(data_ref) => Box::new(data_ref.strings_iter()),
51✔
138
            FeatureDataRef::Float(data_ref) => Box::new(data_ref.strings_iter()),
2✔
139
            FeatureDataRef::Int(data_ref) => Box::new(data_ref.strings_iter()),
1✔
140
            FeatureDataRef::Category(data_ref) => Box::new(data_ref.strings_iter()),
×
141
            FeatureDataRef::Bool(data_ref) => Box::new(data_ref.strings_iter()),
1✔
142
            FeatureDataRef::DateTime(data_ref) => Box::new(data_ref.strings_iter()),
1✔
143
        }
144
    }
56✔
145

146
    /// Creates an iterator over all values as [`Option<f64>`]
147
    /// Null values or non-convertible values are [`None`]
148
    pub fn float_options_iter(&self) -> Box<dyn Iterator<Item = Option<f64>> + '_> {
44✔
149
        match self {
44✔
150
            FeatureDataRef::Text(data_ref) => Box::new(data_ref.float_options_iter()),
1✔
151
            FeatureDataRef::Float(data_ref) => Box::new(data_ref.float_options_iter()),
15✔
152
            FeatureDataRef::Int(data_ref) => Box::new(data_ref.float_options_iter()),
26✔
153
            FeatureDataRef::Category(data_ref) => Box::new(data_ref.float_options_iter()),
×
154
            FeatureDataRef::Bool(data_ref) => Box::new(data_ref.float_options_iter()),
1✔
155
            FeatureDataRef::DateTime(data_ref) => Box::new(data_ref.float_options_iter()),
1✔
156
        }
157
    }
44✔
158
}
159

160
/// Common methods for feature data references
161
pub trait DataRef<'r, T>: AsRef<[T]> + Into<FeatureDataRef<'r>>
162
where
163
    T: 'static,
164
{
165
    type StringsIter: Iterator<Item = String>;
166
    type FloatOptionsIter: Iterator<Item = Option<f64>>;
167

168
    /// Computes JSON value lists for data elements
169
    fn json_values(&'r self) -> Box<dyn Iterator<Item = serde_json::Value> + 'r> {
3✔
170
        if self.has_nulls() {
3✔
171
            Box::new(self.as_ref().iter().enumerate().map(move |(i, v)| {
5✔
172
                if self.is_null(i) {
5✔
173
                    serde_json::Value::Null
1✔
174
                } else {
175
                    Self::json_value(v)
4✔
176
                }
177
            }))
5✔
178
        } else {
179
            Box::new(self.as_ref().iter().map(Self::json_value))
2✔
180
        }
181
    }
3✔
182

183
    /// Creates a JSON value out of the owned type
184
    fn json_value(value: &T) -> serde_json::Value;
185

186
    /// Computes a vector of null flags.
187
    fn nulls(&self) -> Vec<bool>;
188

189
    /// Is the `i`th value null?
190
    /// This method panics if `i` is too large.
191
    fn is_null(&self, i: usize) -> bool {
57,581✔
192
        !self.is_valid(i)
57,581✔
193
    }
57,581✔
194

195
    /// Is the `i`th value valid, i.e., not null?
196
    /// This method panics if `i` is too large.
197
    fn is_valid(&self, i: usize) -> bool;
198

199
    /// Is any of the data elements null?
200
    fn has_nulls(&self) -> bool;
201

202
    fn get_unchecked(&self, i: usize) -> FeatureDataValue;
203

204
    /// Number of values
205
    fn len(&self) -> usize;
206

207
    fn is_empty(&self) -> bool {
×
208
        self.len() == 0
×
209
    }
×
210

211
    /// Creates an iterator over all values as string
212
    /// Null values are empty strings.
213
    fn strings_iter(&'r self) -> Self::StringsIter;
214

215
    /// Creates an iterator over all values as [`Option<f64>`]
216
    /// Null values or non-convertible values are [`None`]
217
    fn float_options_iter(&'r self) -> Self::FloatOptionsIter;
218
}
219

220
#[derive(Clone, Debug, PartialEq)]
×
221
pub struct FloatDataRef<'f> {
222
    buffer: &'f [f64],
223
    valid_bitmap: Option<&'f arrow::bitmap::Bitmap>,
224
}
225

226
impl<'f> DataRef<'f, f64> for FloatDataRef<'f> {
227
    fn json_value(value: &f64) -> serde_json::Value {
3✔
228
        (*value).into()
3✔
229
    }
3✔
230

231
    fn nulls(&self) -> Vec<bool> {
5✔
232
        null_bitmap_to_bools(self.valid_bitmap, self.as_ref().len())
5✔
233
    }
5✔
234

235
    fn is_valid(&self, i: usize) -> bool {
94✔
236
        self.valid_bitmap
94✔
237
            .as_ref()
94✔
238
            .map_or(true, |bitmap| bitmap.is_set(i))
94✔
239
    }
94✔
240

241
    fn has_nulls(&self) -> bool {
16✔
242
        self.valid_bitmap.is_some()
16✔
243
    }
16✔
244

245
    fn get_unchecked(&self, i: usize) -> FeatureDataValue {
10✔
246
        if self.has_nulls() {
10✔
247
            FeatureDataValue::NullableFloat(if self.is_null(i) {
×
248
                None
×
249
            } else {
250
                Some(self.as_ref()[i])
×
251
            })
252
        } else {
253
            FeatureDataValue::Float(self.as_ref()[i])
10✔
254
        }
255
    }
10✔
256

257
    type StringsIter = NumberDataRefStringIter<'f, Self, f64>;
258

259
    fn strings_iter(&'f self) -> Self::StringsIter {
2✔
260
        NumberDataRefStringIter::new(self)
2✔
261
    }
2✔
262

263
    fn len(&self) -> usize {
110✔
264
        self.buffer.len()
110✔
265
    }
110✔
266

267
    type FloatOptionsIter = NumberDataRefFloatOptionIter<'f, Self, f64>;
268

269
    fn float_options_iter(&'f self) -> Self::FloatOptionsIter {
18✔
270
        NumberDataRefFloatOptionIter::new(self)
18✔
271
    }
18✔
272
}
273

274
pub struct NumberDataRefStringIter<'r, D, T>
275
where
276
    D: DataRef<'r, T>,
277
    T: 'static,
278
{
279
    data_ref: &'r D,
280
    i: usize,
281
    t: PhantomData<T>,
282
}
283

284
impl<'r, D, T> NumberDataRefStringIter<'r, D, T>
285
where
286
    D: DataRef<'r, T>,
287
    T: 'static,
288
{
289
    pub fn new(data_ref: &'r D) -> Self {
5✔
290
        Self {
5✔
291
            data_ref,
5✔
292
            i: 0,
5✔
293
            t: PhantomData::default(),
5✔
294
        }
5✔
295
    }
5✔
296
}
297

298
impl<'f, D, T> Iterator for NumberDataRefStringIter<'f, D, T>
299
where
300
    D: DataRef<'f, T>,
301
    T: 'static + ToString,
302
{
303
    type Item = String;
304

305
    fn next(&mut self) -> Option<Self::Item> {
23✔
306
        if self.i >= self.data_ref.len() {
23✔
307
            return None;
5✔
308
        }
18✔
309

18✔
310
        let i = self.i;
18✔
311
        self.i += 1;
18✔
312

18✔
313
        if self.data_ref.is_null(i) {
18✔
314
            return Some(String::default());
5✔
315
        }
13✔
316

13✔
317
        Some(self.data_ref.as_ref()[i].to_string())
13✔
318
    }
23✔
319
}
320

321
pub struct NumberDataRefFloatOptionIter<'r, D, T>
322
where
323
    D: DataRef<'r, T>,
324
    T: 'static,
325
{
326
    data_ref: &'r D,
327
    i: usize,
328
    t: PhantomData<T>,
329
}
330

331
impl<'r, D, T> NumberDataRefFloatOptionIter<'r, D, T>
332
where
333
    D: DataRef<'r, T>,
334
    T: 'static,
335
{
336
    pub fn new(data_ref: &'r D) -> Self {
44✔
337
        Self {
44✔
338
            data_ref,
44✔
339
            i: 0,
44✔
340
            t: PhantomData::default(),
44✔
341
        }
44✔
342
    }
44✔
343
}
344

345
impl<'f, D, T> Iterator for NumberDataRefFloatOptionIter<'f, D, T>
346
where
347
    D: DataRef<'f, T>,
348
    T: 'static + AsPrimitive<f64>,
349
{
350
    type Item = Option<f64>;
351

352
    fn next(&mut self) -> Option<Self::Item> {
57,577✔
353
        if self.i >= self.data_ref.len() {
57,577✔
354
            return None;
32✔
355
        }
57,545✔
356

57,545✔
357
        let i = self.i;
57,545✔
358
        self.i += 1;
57,545✔
359

57,545✔
360
        Some(if self.data_ref.is_null(i) {
57,545✔
361
            None
22✔
362
        } else {
363
            Some(self.data_ref.as_ref()[i].as_())
57,523✔
364
        })
365
    }
57,577✔
366
}
367

368
impl AsRef<[f64]> for FloatDataRef<'_> {
369
    fn as_ref(&self) -> &[f64] {
103✔
370
        self.buffer
103✔
371
    }
103✔
372
}
373

374
impl<'f> From<FloatDataRef<'f>> for FeatureDataRef<'f> {
375
    fn from(data_ref: FloatDataRef<'f>) -> FeatureDataRef<'f> {
37✔
376
        FeatureDataRef::Float(data_ref)
37✔
377
    }
37✔
378
}
379

380
impl<'f> FloatDataRef<'f> {
381
    pub fn new(buffer: &'f [f64], null_bitmap: Option<&'f arrow::bitmap::Bitmap>) -> Self {
40✔
382
        Self {
40✔
383
            buffer,
40✔
384
            valid_bitmap: null_bitmap,
40✔
385
        }
40✔
386
    }
40✔
387
}
388

389
#[derive(Clone, Debug, PartialEq)]
1✔
390
pub struct IntDataRef<'f> {
391
    buffer: &'f [i64],
392
    valid_bitmap: Option<&'f arrow::bitmap::Bitmap>,
393
}
394

395
impl<'f> IntDataRef<'f> {
396
    pub fn new(buffer: &'f [i64], null_bitmap: Option<&'f arrow::bitmap::Bitmap>) -> Self {
70✔
397
        Self {
70✔
398
            buffer,
70✔
399
            valid_bitmap: null_bitmap,
70✔
400
        }
70✔
401
    }
70✔
402
}
403

404
impl<'f> DataRef<'f, i64> for IntDataRef<'f> {
405
    fn json_value(value: &i64) -> serde_json::Value {
5✔
406
        (*value).into()
5✔
407
    }
5✔
408

409
    fn nulls(&self) -> Vec<bool> {
2✔
410
        null_bitmap_to_bools(self.valid_bitmap, self.as_ref().len())
2✔
411
    }
2✔
412

413
    fn is_valid(&self, i: usize) -> bool {
57,475✔
414
        self.valid_bitmap
57,475✔
415
            .as_ref()
57,475✔
416
            .map_or(true, |bitmap| bitmap.is_set(i))
57,475✔
417
    }
57,475✔
418

419
    fn has_nulls(&self) -> bool {
38✔
420
        self.valid_bitmap.is_some()
38✔
421
    }
38✔
422

423
    fn get_unchecked(&self, i: usize) -> FeatureDataValue {
30✔
424
        if self.has_nulls() {
30✔
425
            FeatureDataValue::NullableInt(if self.is_null(i) {
7✔
426
                None
4✔
427
            } else {
428
                Some(self.as_ref()[i])
3✔
429
            })
430
        } else {
431
            FeatureDataValue::Int(self.as_ref()[i])
23✔
432
        }
433
    }
30✔
434

435
    type StringsIter = NumberDataRefStringIter<'f, Self, i64>;
436

437
    fn strings_iter(&'f self) -> Self::StringsIter {
1✔
438
        NumberDataRefStringIter::new(self)
1✔
439
    }
1✔
440

441
    fn len(&self) -> usize {
57,482✔
442
        self.buffer.len()
57,482✔
443
    }
57,482✔
444

445
    type FloatOptionsIter = NumberDataRefFloatOptionIter<'f, Self, i64>;
446

447
    fn float_options_iter(&'f self) -> Self::FloatOptionsIter {
26✔
448
        NumberDataRefFloatOptionIter::new(self)
26✔
449
    }
26✔
450
}
451

452
impl AsRef<[i64]> for IntDataRef<'_> {
453
    fn as_ref(&self) -> &[i64] {
57,528✔
454
        self.buffer
57,528✔
455
    }
57,528✔
456
}
457

458
impl<'f> From<IntDataRef<'f>> for FeatureDataRef<'f> {
459
    fn from(data_ref: IntDataRef<'f>) -> FeatureDataRef<'f> {
68✔
460
        FeatureDataRef::Int(data_ref)
68✔
461
    }
68✔
462
}
463

464
fn null_bitmap_to_bools(null_bitmap: Option<&Bitmap>, len: usize) -> Vec<bool> {
465
    if let Some(nulls) = null_bitmap {
8✔
466
        (0..len).map(|i| !nulls.is_set(i)).collect()
28✔
467
    } else {
468
        vec![false; len]
×
469
    }
470
}
8✔
471

472
#[derive(Clone, Debug, PartialEq)]
×
473
pub struct BoolDataRef<'f> {
474
    buffer: Vec<bool>,
475
    valid_bitmap: Option<&'f arrow::bitmap::Bitmap>,
476
}
477

478
impl<'f> BoolDataRef<'f> {
479
    pub fn new(buffer: Vec<bool>, null_bitmap: Option<&'f arrow::bitmap::Bitmap>) -> Self {
2✔
480
        Self {
2✔
481
            buffer,
2✔
482
            valid_bitmap: null_bitmap,
2✔
483
        }
2✔
484
    }
2✔
485
}
486

487
impl<'f> DataRef<'f, bool> for BoolDataRef<'f> {
488
    fn json_value(value: &bool) -> serde_json::Value {
×
489
        (*value).into()
×
490
    }
×
491

492
    fn nulls(&self) -> Vec<bool> {
×
493
        null_bitmap_to_bools(self.valid_bitmap, self.as_ref().len())
×
494
    }
×
495

496
    fn is_valid(&self, i: usize) -> bool {
6✔
497
        self.valid_bitmap
6✔
498
            .as_ref()
6✔
499
            .map_or(true, |bitmap| bitmap.is_set(i))
6✔
500
    }
6✔
501

502
    fn has_nulls(&self) -> bool {
×
503
        self.valid_bitmap.is_some()
×
504
    }
×
505

506
    fn get_unchecked(&self, i: usize) -> FeatureDataValue {
×
507
        if self.has_nulls() {
×
508
            FeatureDataValue::NullableBool(if self.is_null(i) {
×
509
                None
×
510
            } else {
511
                Some(self.as_ref()[i])
×
512
            })
513
        } else {
514
            FeatureDataValue::Bool(self.as_ref()[i])
×
515
        }
516
    }
×
517

518
    type StringsIter = NumberDataRefStringIter<'f, Self, bool>;
519

520
    fn strings_iter(&'f self) -> Self::StringsIter {
1✔
521
        NumberDataRefStringIter::new(self)
1✔
522
    }
1✔
523

524
    fn len(&self) -> usize {
8✔
525
        self.buffer.len()
8✔
526
    }
8✔
527

528
    type FloatOptionsIter = BoolDataRefFloatOptionIter<'f>;
529

530
    fn float_options_iter(&'f self) -> Self::FloatOptionsIter {
1✔
531
        BoolDataRefFloatOptionIter::new(self)
1✔
532
    }
1✔
533
}
534

535
impl AsRef<[bool]> for BoolDataRef<'_> {
536
    fn as_ref(&self) -> &[bool] {
4✔
537
        &self.buffer
4✔
538
    }
4✔
539
}
540

541
impl<'f> From<BoolDataRef<'f>> for FeatureDataRef<'f> {
542
    fn from(data_ref: BoolDataRef<'f>) -> Self {
2✔
543
        FeatureDataRef::Bool(data_ref)
2✔
544
    }
2✔
545
}
546

547
pub struct BoolDataRefFloatOptionIter<'f> {
548
    data_ref: &'f BoolDataRef<'f>,
549
    i: usize,
550
}
551

552
impl<'f> BoolDataRefFloatOptionIter<'f> {
553
    pub fn new(data_ref: &'f BoolDataRef<'f>) -> Self {
1✔
554
        Self { data_ref, i: 0 }
1✔
555
    }
1✔
556
}
557

558
impl<'f> Iterator for BoolDataRefFloatOptionIter<'f> {
559
    type Item = Option<f64>;
560

561
    fn next(&mut self) -> Option<Self::Item> {
4✔
562
        if self.i >= self.data_ref.len() {
4✔
563
            return None;
1✔
564
        }
3✔
565

3✔
566
        let i = self.i;
3✔
567
        self.i += 1;
3✔
568

3✔
569
        Some(if self.data_ref.is_null(i) {
3✔
570
            None
1✔
571
        } else {
572
            Some(f64::from(u8::from(self.data_ref.as_ref()[i])))
2✔
573
        })
574
    }
4✔
575
}
576

577
#[derive(Clone, Debug, PartialEq)]
×
578
pub struct DateTimeDataRef<'f> {
579
    buffer: &'f [TimeInstance],
580
    valid_bitmap: Option<&'f arrow::bitmap::Bitmap>,
581
}
582

583
impl<'f> DateTimeDataRef<'f> {
584
    pub fn new(buffer: &'f [TimeInstance], null_bitmap: Option<&'f arrow::bitmap::Bitmap>) -> Self {
2✔
585
        Self {
2✔
586
            buffer,
2✔
587
            valid_bitmap: null_bitmap,
2✔
588
        }
2✔
589
    }
2✔
590
}
591

592
impl<'f> DataRef<'f, TimeInstance> for DateTimeDataRef<'f> {
593
    fn json_value(value: &TimeInstance) -> serde_json::Value {
×
594
        serde_json::to_value(value).expect("TimeInstance can be serialized")
×
595
    }
×
596

597
    fn nulls(&self) -> Vec<bool> {
×
598
        null_bitmap_to_bools(self.valid_bitmap, self.as_ref().len())
×
599
    }
×
600

601
    fn is_valid(&self, i: usize) -> bool {
6✔
602
        self.valid_bitmap
6✔
603
            .as_ref()
6✔
604
            .map_or(true, |bitmap| bitmap.is_set(i))
6✔
605
    }
6✔
606

607
    fn has_nulls(&self) -> bool {
×
608
        self.valid_bitmap.is_some()
×
609
    }
×
610

611
    fn get_unchecked(&self, i: usize) -> FeatureDataValue {
×
612
        if self.has_nulls() {
×
613
            FeatureDataValue::NullableDateTime(if self.is_null(i) {
×
614
                None
×
615
            } else {
616
                Some(self.as_ref()[i])
×
617
            })
618
        } else {
619
            FeatureDataValue::DateTime(self.as_ref()[i])
×
620
        }
621
    }
×
622

623
    type StringsIter = NumberDataRefStringIter<'f, Self, TimeInstance>;
624

625
    fn strings_iter(&'f self) -> Self::StringsIter {
1✔
626
        NumberDataRefStringIter::new(self)
1✔
627
    }
1✔
628

629
    fn len(&self) -> usize {
8✔
630
        self.buffer.len()
8✔
631
    }
8✔
632

633
    type FloatOptionsIter = DateTimeDataRefFloatOptionIter<'f>;
634

635
    fn float_options_iter(&'f self) -> Self::FloatOptionsIter {
1✔
636
        Self::FloatOptionsIter::new(self)
1✔
637
    }
1✔
638
}
639

640
impl AsRef<[TimeInstance]> for DateTimeDataRef<'_> {
641
    fn as_ref(&self) -> &[TimeInstance] {
4✔
642
        self.buffer
4✔
643
    }
4✔
644
}
645

646
impl<'f> From<DateTimeDataRef<'f>> for FeatureDataRef<'f> {
647
    fn from(data_ref: DateTimeDataRef<'f>) -> Self {
2✔
648
        FeatureDataRef::DateTime(data_ref)
2✔
649
    }
2✔
650
}
651

652
pub struct DateTimeDataRefFloatOptionIter<'f> {
653
    data_ref: &'f DateTimeDataRef<'f>,
654
    i: usize,
655
}
656

657
impl<'f> DateTimeDataRefFloatOptionIter<'f> {
658
    pub fn new(data_ref: &'f DateTimeDataRef<'f>) -> Self {
1✔
659
        Self { data_ref, i: 0 }
1✔
660
    }
1✔
661
}
662

663
impl<'f> Iterator for DateTimeDataRefFloatOptionIter<'f> {
664
    type Item = Option<f64>;
665

666
    fn next(&mut self) -> Option<Self::Item> {
4✔
667
        if self.i >= self.data_ref.len() {
4✔
668
            return None;
1✔
669
        }
3✔
670

3✔
671
        let i = self.i;
3✔
672
        self.i += 1;
3✔
673

3✔
674
        Some(if self.data_ref.is_null(i) {
3✔
675
            None
1✔
676
        } else {
677
            Some(self.data_ref.as_ref()[i].inner() as f64)
2✔
678
        })
679
    }
4✔
680
}
681

682
#[derive(Clone, Debug, PartialEq)]
×
683
pub struct CategoryDataRef<'f> {
684
    buffer: &'f [u8],
685
    valid_bitmap: Option<&'f arrow::bitmap::Bitmap>,
686
}
687

688
impl<'f> DataRef<'f, u8> for CategoryDataRef<'f> {
689
    fn json_value(value: &u8) -> serde_json::Value {
×
690
        (*value).into()
×
691
    }
×
692

693
    fn nulls(&self) -> Vec<bool> {
×
694
        null_bitmap_to_bools(self.valid_bitmap, self.as_ref().len())
×
695
    }
×
696

697
    fn is_valid(&self, i: usize) -> bool {
×
698
        self.valid_bitmap
×
699
            .as_ref()
×
700
            .map_or(true, |bitmap| bitmap.is_set(i))
×
701
    }
×
702

703
    fn has_nulls(&self) -> bool {
1✔
704
        self.valid_bitmap.is_some()
1✔
705
    }
1✔
706

707
    fn get_unchecked(&self, i: usize) -> FeatureDataValue {
×
708
        if self.has_nulls() {
×
709
            FeatureDataValue::NullableCategory(if self.is_null(i) {
×
710
                None
×
711
            } else {
712
                Some(self.as_ref()[i])
×
713
            })
714
        } else {
715
            FeatureDataValue::Category(self.as_ref()[i])
×
716
        }
717
    }
×
718

719
    type StringsIter = NumberDataRefStringIter<'f, Self, u8>;
720

721
    fn strings_iter(&'f self) -> Self::StringsIter {
×
722
        NumberDataRefStringIter::new(self)
×
723
    }
×
724

725
    fn len(&self) -> usize {
×
726
        self.buffer.len()
×
727
    }
×
728

729
    type FloatOptionsIter = NumberDataRefFloatOptionIter<'f, Self, u8>;
730

731
    fn float_options_iter(&'f self) -> Self::FloatOptionsIter {
×
732
        NumberDataRefFloatOptionIter::new(self)
×
733
    }
×
734
}
735

736
impl AsRef<[u8]> for CategoryDataRef<'_> {
737
    fn as_ref(&self) -> &[u8] {
1✔
738
        self.buffer
1✔
739
    }
1✔
740
}
741

742
impl<'f> From<CategoryDataRef<'f>> for FeatureDataRef<'f> {
743
    fn from(data_ref: CategoryDataRef<'f>) -> FeatureDataRef<'f> {
×
744
        FeatureDataRef::Category(data_ref)
×
745
    }
×
746
}
747

748
impl<'f> CategoryDataRef<'f> {
749
    pub fn new(buffer: &'f [u8], null_bitmap: Option<&'f arrow::bitmap::Bitmap>) -> Self {
1✔
750
        Self {
1✔
751
            buffer,
1✔
752
            valid_bitmap: null_bitmap,
1✔
753
        }
1✔
754
    }
1✔
755
}
756

757
unsafe fn byte_ptr_to_str<'d>(bytes: *const u8, length: usize) -> &'d str {
86✔
758
    let text_ref = slice::from_raw_parts(bytes, length);
86✔
759
    str::from_utf8_unchecked(text_ref)
86✔
760
}
86✔
761

762
/// A reference to nullable text data
763
///
764
/// # Examples
765
///
766
/// ```rust
767
/// use geoengine_datatypes::primitives::TextDataRef;
768
/// use arrow::array::{StringBuilder, Array};
769
///
770
/// let string_array = {
771
///     let mut builder = StringBuilder::with_capacity(3, 6+3);
772
///     builder.append_value("foobar");
773
///     builder.append_null();
774
///     builder.append_value("bar");
775
///     builder.finish()
776
/// };
777
///
778
/// assert_eq!(string_array.len(), 3);
779
///
780
/// let text_data_ref = TextDataRef::new(string_array.value_data(), string_array.value_offsets(), string_array.data_ref().null_bitmap());
781
///
782
/// assert_eq!(text_data_ref.as_ref().len(), 9);
783
/// assert_eq!(text_data_ref.offsets().len(), 4);
784
///
785
/// assert_eq!(text_data_ref.text_at(0).unwrap(), Some("foobar"));
786
/// assert_eq!(text_data_ref.text_at(1).unwrap(), None);
787
/// assert_eq!(text_data_ref.text_at(2).unwrap(), Some("bar"));
788
/// assert!(text_data_ref.text_at(3).is_err());
789
/// ```
790
///
791
#[derive(Clone, Debug, PartialEq)]
1✔
792
pub struct TextDataRef<'f> {
793
    data_buffer: &'f [u8],
794
    offsets: &'f [i32],
795
    valid_bitmap: Option<&'f arrow::bitmap::Bitmap>,
796
}
797

798
impl<'f> AsRef<[u8]> for TextDataRef<'f> {
799
    fn as_ref(&self) -> &[u8] {
×
800
        self.data_buffer
×
801
    }
×
802
}
803

804
impl<'r> DataRef<'r, u8> for TextDataRef<'r> {
805
    fn json_values(&'r self) -> Box<dyn Iterator<Item = serde_json::Value> + 'r> {
1✔
806
        let offsets = self.offsets;
1✔
807
        let number_of_values = offsets.len() - 1;
1✔
808

1✔
809
        Box::new((0..number_of_values).map(move |pos| {
3✔
810
            let start = offsets[pos];
3✔
811
            let end = offsets[pos + 1];
3✔
812

3✔
813
            if start == end {
3✔
814
                return if self.is_valid(pos) {
1✔
815
                    serde_json::Value::String(String::default())
×
816
                } else {
817
                    serde_json::Value::Null
1✔
818
                };
819
            }
2✔
820

2✔
821
            let text = unsafe {
2✔
822
                byte_ptr_to_str(
2✔
823
                    self.data_buffer[start as usize..].as_ptr(),
2✔
824
                    (end - start) as usize,
2✔
825
                )
2✔
826
            };
2✔
827

2✔
828
            text.into()
2✔
829
        }))
3✔
830
    }
1✔
831

832
    fn json_value(value: &u8) -> Value {
×
833
        (*value).into()
×
834
    }
×
835

836
    /// A null vector for text data
837
    ///
838
    /// # Examples
839
    ///
840
    /// ```rust
841
    /// use geoengine_datatypes::primitives::{TextDataRef, DataRef};
842
    /// use arrow::array::{StringBuilder, Array};
843
    ///
844
    /// let string_array = {
845
    ///     let mut builder = StringBuilder::with_capacity(3, 6+3);
846
    ///     builder.append_value("foobar");
847
    ///     builder.append_null();
848
    ///     builder.append_value("bar");
849
    ///     builder.finish()
850
    /// };
851
    ///
852
    /// assert_eq!(string_array.len(), 3);
853
    ///
854
    /// let text_data_ref = TextDataRef::new(string_array.value_data(), string_array.value_offsets(), string_array.data_ref().null_bitmap());
855
    ///
856
    /// assert_eq!(text_data_ref.nulls(), vec![false, true, false]);
857
    /// ```
858
    ///
859
    fn nulls(&self) -> Vec<bool> {
1✔
860
        null_bitmap_to_bools(self.valid_bitmap, self.offsets.len() - 1)
1✔
861
    }
1✔
862

863
    fn is_valid(&self, i: usize) -> bool {
9✔
864
        self.valid_bitmap
9✔
865
            .as_ref()
9✔
866
            .map_or(true, |bitmap| bitmap.is_set(i))
9✔
867
    }
9✔
868

869
    fn has_nulls(&self) -> bool {
21✔
870
        self.valid_bitmap.is_some()
21✔
871
    }
21✔
872

873
    fn get_unchecked(&self, i: usize) -> FeatureDataValue {
19✔
874
        let text = self.text_at(i).expect("unchecked").map(ToString::to_string);
19✔
875

19✔
876
        if self.has_nulls() {
19✔
877
            FeatureDataValue::NullableText(text)
8✔
878
        } else {
879
            FeatureDataValue::Text(text.expect("cannot be null"))
11✔
880
        }
881
    }
19✔
882

883
    type StringsIter = TextDataRefStringIter<'r>;
884

885
    fn strings_iter(&'r self) -> Self::StringsIter {
51✔
886
        Self::StringsIter::new(self)
51✔
887
    }
51✔
888

889
    fn len(&self) -> usize {
×
890
        self.offsets.len() - 1
×
891
    }
×
892

893
    type FloatOptionsIter = TextDataRefFloatOptionIter<'r>;
894

895
    fn float_options_iter(&'r self) -> Self::FloatOptionsIter {
1✔
896
        Self::FloatOptionsIter::new(self)
1✔
897
    }
1✔
898
}
899

900
pub struct TextDataRefStringIter<'r> {
901
    data_ref: &'r TextDataRef<'r>,
902
    i: usize,
903
}
904

905
impl<'r> TextDataRefStringIter<'r> {
906
    pub fn new(data_ref: &'r TextDataRef<'r>) -> Self {
51✔
907
        Self { data_ref, i: 0 }
51✔
908
    }
51✔
909
}
910

911
impl<'r> Iterator for TextDataRefStringIter<'r> {
912
    type Item = String;
913

914
    fn next(&mut self) -> Option<Self::Item> {
113✔
915
        let i = self.i;
113✔
916
        self.i += 1;
113✔
917

113✔
918
        self.data_ref
113✔
919
            .text_at(i)
113✔
920
            .map(|text_option| match text_option {
113✔
921
                Some(text) => text.to_owned(),
60✔
922
                None => String::default(),
2✔
923
            })
113✔
924
            .ok()
113✔
925
    }
113✔
926
}
927

928
pub struct TextDataRefFloatOptionIter<'r> {
929
    data_ref: &'r TextDataRef<'r>,
930
    i: usize,
931
}
932

933
impl<'r> TextDataRefFloatOptionIter<'r> {
934
    pub fn new(data_ref: &'r TextDataRef<'r>) -> Self {
1✔
935
        Self { data_ref, i: 0 }
1✔
936
    }
1✔
937
}
938

939
impl<'r> Iterator for TextDataRefFloatOptionIter<'r> {
940
    type Item = Option<f64>;
941

942
    fn next(&mut self) -> Option<Self::Item> {
4✔
943
        let i = self.i;
4✔
944
        self.i += 1;
4✔
945

4✔
946
        self.data_ref
4✔
947
            .text_at(i)
4✔
948
            .map(|text_option| match text_option {
4✔
949
                Some(text) => text.parse().ok(),
2✔
950
                None => None,
1✔
951
            })
4✔
952
            .ok()
4✔
953
    }
4✔
954
}
955

956
impl<'r> From<TextDataRef<'r>> for FeatureDataRef<'r> {
957
    fn from(data_ref: TextDataRef<'r>) -> Self {
64✔
958
        Self::Text(data_ref)
64✔
959
    }
64✔
960
}
961

962
impl<'r> TextDataRef<'r> {
963
    pub fn new(
64✔
964
        data_buffer: &'r [u8],
64✔
965
        offsets: &'r [i32],
64✔
966
        valid_bitmap: Option<&'r arrow::bitmap::Bitmap>,
64✔
967
    ) -> Self {
64✔
968
        Self {
64✔
969
            data_buffer,
64✔
970
            offsets,
64✔
971
            valid_bitmap,
64✔
972
        }
64✔
973
    }
64✔
974

975
    /// Returns the offsets of the individual strings
976
    pub fn offsets(&self) -> &[i32] {
×
977
        self.offsets
×
978
    }
×
979

980
    /// Returns the text reference at a certain position in the feature collection
981
    ///
982
    /// # Errors
983
    ///
984
    /// This method fails if `pos` is out of bounds
985
    ///
986
    pub fn text_at(&self, pos: usize) -> Result<Option<&str>> {
144✔
987
        ensure!(
144✔
988
            pos < (self.offsets.len() - 1),
144✔
989
            error::FeatureData {
52✔
990
                details: "Position must be in data range"
52✔
991
            }
52✔
992
        );
993

994
        let start = self.offsets[pos];
92✔
995
        let end = self.offsets[pos + 1];
92✔
996

92✔
997
        if start == end {
92✔
998
            return Ok(if self.is_valid(pos) { Some("") } else { None });
8✔
999
        }
84✔
1000

84✔
1001
        let text = unsafe {
84✔
1002
            byte_ptr_to_str(
84✔
1003
                self.data_buffer[start as usize..].as_ptr(),
84✔
1004
                (end - start) as usize,
84✔
1005
            )
84✔
1006
        };
84✔
1007

84✔
1008
        Ok(Some(text))
84✔
1009
    }
144✔
1010
}
1011

1012
impl FeatureDataType {
1013
    pub fn arrow_data_type(self) -> arrow::datatypes::DataType {
1,532✔
1014
        match self {
1,532✔
1015
            Self::Text => arrow::datatypes::DataType::Utf8,
586✔
1016
            Self::Float => arrow::datatypes::DataType::Float64,
711✔
1017
            Self::Int => arrow::datatypes::DataType::Int64,
223✔
1018
            Self::Category => arrow::datatypes::DataType::UInt8,
×
1019
            Self::Bool => arrow::datatypes::DataType::Boolean,
6✔
1020
            Self::DateTime => arrow::datatypes::DataType::Date64,
6✔
1021
        }
1022
    }
1,532✔
1023

1024
    #[allow(clippy::unused_self)]
1025
    pub fn nullable(self) -> bool {
1,532✔
1026
        true
1,532✔
1027
    }
1,532✔
1028

1029
    pub fn arrow_builder(self, len: usize) -> Box<dyn arrow::array::ArrayBuilder> {
816✔
1030
        match self {
816✔
1031
            Self::Text => Box::new(arrow::array::StringBuilder::with_capacity(len, 0)),
359✔
1032
            Self::Float => Box::new(arrow::array::Float64Builder::with_capacity(len)),
360✔
1033
            Self::Int => Box::new(arrow::array::Int64Builder::with_capacity(len)),
93✔
1034
            Self::Category => Box::new(arrow::array::UInt8Builder::with_capacity(len)),
×
1035
            Self::Bool => Box::new(arrow::array::BooleanBuilder::with_capacity(len)),
2✔
1036
            Self::DateTime => Box::new(arrow::array::Date64Builder::with_capacity(len)),
2✔
1037
        }
1038
    }
816✔
1039
}
1040

1041
impl FeatureData {
1042
    pub fn arrow_data_type(&self) -> arrow::datatypes::DataType {
270✔
1043
        FeatureDataType::from(self).arrow_data_type()
270✔
1044
    }
270✔
1045

1046
    pub fn nullable(&self) -> bool {
270✔
1047
        FeatureDataType::from(self).nullable()
270✔
1048
    }
270✔
1049

1050
    pub fn len(&self) -> usize {
284✔
1051
        match self {
284✔
1052
            FeatureData::Text(v) => v.len(),
25✔
1053
            FeatureData::NullableText(v) => v.len(),
42✔
1054
            FeatureData::Float(v) => v.len(),
36✔
1055
            FeatureData::NullableFloat(v) => v.len(),
45✔
1056
            FeatureData::Int(v) => v.len(),
88✔
1057
            FeatureData::NullableInt(v) => v.len(),
40✔
1058
            FeatureData::Category(v) => v.len(),
×
1059
            FeatureData::NullableCategory(v) => v.len(),
×
1060
            FeatureData::Bool(v) => v.len(),
2✔
1061
            FeatureData::NullableBool(v) => v.len(),
2✔
1062
            FeatureData::DateTime(v) => v.len(),
2✔
1063
            FeatureData::NullableDateTime(v) => v.len(),
2✔
1064
        }
1065
    }
284✔
1066

1067
    pub fn is_empty(&self) -> bool {
×
1068
        self.len() == 0
×
1069
    }
×
1070

1071
    /// Creates an `arrow` array builder.
1072
    pub(crate) fn arrow_builder(&self) -> Box<dyn arrow::array::ArrayBuilder> {
270✔
1073
        match self {
270✔
1074
            Self::Text(v) => {
25✔
1075
                let mut builder = arrow::array::StringBuilder::with_capacity(
25✔
1076
                    v.len(),
25✔
1077
                    v.iter().map(String::len).sum(),
25✔
1078
                );
25✔
1079
                for text in v {
83✔
1080
                    builder.append_value(text);
58✔
1081
                }
58✔
1082
                Box::new(builder)
25✔
1083
            }
1084
            Self::NullableText(v) => {
42✔
1085
                let mut builder = arrow::array::StringBuilder::with_capacity(
42✔
1086
                    v.len(),
42✔
1087
                    v.iter()
42✔
1088
                        .map(|text_option| text_option.as_ref().map_or(0, String::len))
110✔
1089
                        .sum(),
42✔
1090
                );
42✔
1091
                for text_opt in v {
152✔
1092
                    if let Some(text) = text_opt {
110✔
1093
                        builder.append_value(text);
77✔
1094
                    } else {
77✔
1095
                        builder.append_null();
33✔
1096
                    }
33✔
1097
                }
1098
                Box::new(builder)
42✔
1099
            }
1100
            Self::Float(v) => {
36✔
1101
                let mut builder = arrow::array::Float64Builder::with_capacity(v.len());
36✔
1102
                builder.append_slice(v);
36✔
1103
                Box::new(builder)
36✔
1104
            }
1105
            Self::NullableFloat(v) => {
41✔
1106
                let mut builder = arrow::array::Float64Builder::with_capacity(v.len());
41✔
1107
                for &number_option in v {
196✔
1108
                    builder.append_option(number_option);
155✔
1109
                }
155✔
1110
                Box::new(builder)
41✔
1111
            }
1112
            Self::Int(v) => {
88✔
1113
                let mut builder = arrow::array::Int64Builder::with_capacity(v.len());
88✔
1114
                builder.append_slice(v);
88✔
1115
                Box::new(builder)
88✔
1116
            }
1117
            Self::NullableInt(v) => {
30✔
1118
                let mut builder = arrow::array::Int64Builder::with_capacity(v.len());
30✔
1119
                for &int_option in v {
119✔
1120
                    builder.append_option(int_option);
89✔
1121
                }
89✔
1122
                Box::new(builder)
30✔
1123
            }
1124
            Self::Category(v) => {
×
1125
                let mut builder = arrow::array::UInt8Builder::with_capacity(v.len());
×
1126
                builder.append_slice(v);
×
1127
                Box::new(builder)
×
1128
            }
1129
            Self::NullableCategory(v) => {
×
1130
                let mut builder = arrow::array::UInt8Builder::with_capacity(v.len());
×
1131
                for &float_option in v {
×
1132
                    builder.append_option(float_option);
×
1133
                }
×
1134
                Box::new(builder)
×
1135
            }
1136
            FeatureData::Bool(v) => {
2✔
1137
                let mut builder = arrow::array::BooleanBuilder::with_capacity(v.len());
2✔
1138
                builder.append_slice(v);
2✔
1139
                Box::new(builder)
2✔
1140
            }
1141
            FeatureData::NullableBool(v) => {
2✔
1142
                let mut builder = arrow::array::BooleanBuilder::with_capacity(v.len());
2✔
1143
                for &bool_option in v {
8✔
1144
                    builder.append_option(bool_option);
6✔
1145
                }
6✔
1146
                Box::new(builder)
2✔
1147
            }
1148
            FeatureData::DateTime(v) => {
2✔
1149
                let mut builder = arrow::array::Date64Builder::with_capacity(v.len());
2✔
1150
                let x: Vec<_> = v.iter().map(|x| x.inner()).collect();
6✔
1151
                builder.append_slice(&x);
2✔
1152
                Box::new(builder)
2✔
1153
            }
1154
            FeatureData::NullableDateTime(v) => {
2✔
1155
                let mut builder = arrow::array::Date64Builder::with_capacity(v.len());
2✔
1156
                for &dt_option in v {
8✔
1157
                    builder.append_option(dt_option.map(TimeInstance::inner));
6✔
1158
                }
6✔
1159
                Box::new(builder)
2✔
1160
            }
1161
        }
1162
    }
270✔
1163
}
1164

1165
impl From<&FeatureData> for FeatureDataType {
1166
    fn from(value: &FeatureData) -> Self {
810✔
1167
        match value {
810✔
1168
            FeatureData::Text(_) | FeatureData::NullableText(_) => Self::Text,
201✔
1169
            FeatureData::Float(_) | FeatureData::NullableFloat(_) => Self::Float,
231✔
1170
            FeatureData::Int(_) | FeatureData::NullableInt(_) => Self::Int,
354✔
1171
            FeatureData::Category(_) | FeatureData::NullableCategory(_) => Self::Category,
×
1172
            FeatureData::Bool(_) | FeatureData::NullableBool(_) => Self::Bool,
12✔
1173
            FeatureData::DateTime(_) | FeatureData::NullableDateTime(_) => Self::DateTime,
12✔
1174
        }
1175
    }
810✔
1176
}
1177

1178
impl From<&FeatureDataValue> for FeatureDataType {
1179
    fn from(value: &FeatureDataValue) -> Self {
15,532✔
1180
        match value {
15,532✔
1181
            FeatureDataValue::Text(_) | FeatureDataValue::NullableText(_) => Self::Text,
9,818✔
1182
            FeatureDataValue::Float(_) | FeatureDataValue::NullableFloat(_) => Self::Float,
5,583✔
1183
            FeatureDataValue::Int(_) | FeatureDataValue::NullableInt(_) => Self::Int,
127✔
1184
            FeatureDataValue::Category(_) | FeatureDataValue::NullableCategory(_) => Self::Category,
×
1185
            FeatureDataValue::Bool(_) | FeatureDataValue::NullableBool(_) => Self::Bool,
3✔
1186
            FeatureDataValue::DateTime(_) | FeatureDataValue::NullableDateTime(_) => Self::DateTime,
1✔
1187
        }
1188
    }
15,532✔
1189
}
1190

1191
impl<'f> From<&'f FeatureDataRef<'f>> for FeatureDataType {
1192
    fn from(value: &FeatureDataRef) -> Self {
×
1193
        match value {
×
1194
            FeatureDataRef::Text(_) => Self::Text,
×
1195
            FeatureDataRef::Float(..) => Self::Float,
×
1196
            FeatureDataRef::Int(_) => Self::Int,
×
1197
            FeatureDataRef::Category(_) => Self::Category,
×
1198
            FeatureDataRef::Bool(_) => Self::Bool,
×
1199
            FeatureDataRef::DateTime(_) => Self::DateTime,
×
1200
        }
1201
    }
×
1202
}
1203

1204
impl TryFrom<&FeatureDataValue> for f64 {
1205
    type Error = crate::collections::FeatureCollectionError;
1206

1207
    fn try_from(value: &FeatureDataValue) -> Result<Self, Self::Error> {
3✔
1208
        Ok(match value {
×
1209
            FeatureDataValue::Float(v) | FeatureDataValue::NullableFloat(Some(v)) => *v,
3✔
1210
            _ => return Err(crate::collections::FeatureCollectionError::WrongDataType),
×
1211
        })
1212
    }
3✔
1213
}
1214

1215
impl TryFrom<FeatureDataValue> for f64 {
1216
    type Error = crate::collections::FeatureCollectionError;
1217

1218
    fn try_from(value: FeatureDataValue) -> Result<Self, Self::Error> {
×
1219
        f64::try_from(&value)
×
1220
    }
×
1221
}
1222

1223
impl TryFrom<&FeatureDataValue> for i64 {
1224
    type Error = crate::collections::FeatureCollectionError;
1225

1226
    fn try_from(value: &FeatureDataValue) -> Result<i64, Self::Error> {
13✔
1227
        Ok(match value {
×
1228
            FeatureDataValue::Int(v) | FeatureDataValue::NullableInt(Some(v)) => *v,
12✔
1229
            FeatureDataValue::DateTime(v) | FeatureDataValue::NullableDateTime(Some(v)) => {
1✔
1230
                v.inner()
1✔
1231
            }
1232
            _ => return Err(crate::collections::FeatureCollectionError::WrongDataType),
×
1233
        })
1234
    }
13✔
1235
}
1236

1237
impl TryFrom<FeatureDataValue> for i64 {
1238
    type Error = crate::collections::FeatureCollectionError;
1239

1240
    fn try_from(value: FeatureDataValue) -> Result<i64, Self::Error> {
×
1241
        i64::try_from(&value)
×
1242
    }
×
1243
}
1244

1245
impl<'s> TryFrom<&'s FeatureDataValue> for &'s str {
1246
    type Error = crate::collections::FeatureCollectionError;
1247

1248
    fn try_from(value: &FeatureDataValue) -> Result<&str, Self::Error> {
1✔
1249
        Ok(match value {
×
1250
            FeatureDataValue::Text(v) | FeatureDataValue::NullableText(Some(v)) => v.as_ref(),
1✔
1251
            _ => return Err(crate::collections::FeatureCollectionError::WrongDataType),
×
1252
        })
1253
    }
1✔
1254
}
1255

1256
impl TryFrom<&FeatureDataValue> for bool {
1257
    type Error = crate::collections::FeatureCollectionError;
1258

1259
    fn try_from(value: &FeatureDataValue) -> Result<bool, Self::Error> {
1✔
1260
        Ok(match value {
×
1261
            FeatureDataValue::Bool(v) | FeatureDataValue::NullableBool(Some(v)) => *v,
1✔
1262
            _ => return Err(crate::collections::FeatureCollectionError::WrongDataType),
×
1263
        })
1264
    }
1✔
1265
}
1266

1267
impl TryFrom<&FeatureDataValue> for TimeInstance {
1268
    type Error = crate::collections::FeatureCollectionError;
1269

1270
    fn try_from(value: &FeatureDataValue) -> Result<TimeInstance, Self::Error> {
×
1271
        Ok(match value {
×
1272
            FeatureDataValue::DateTime(v) | FeatureDataValue::NullableDateTime(Some(v)) => *v,
×
1273
            _ => return Err(crate::collections::FeatureCollectionError::WrongDataType),
×
1274
        })
1275
    }
×
1276
}
1277

1278
#[cfg(test)]
1279
mod tests {
1280
    use crate::{
1281
        collections::{DataCollection, FeatureCollectionInfos},
1282
        primitives::{NoGeometry, TimeInterval},
1283
    };
1284

1285
    use super::*;
1286

1287
    #[test]
1✔
1288
    fn strings_iter() {
1✔
1289
        let collection = DataCollection::from_slices(
1✔
1290
            &[] as &[NoGeometry],
1✔
1291
            &[TimeInterval::default(); 3],
1✔
1292
            &[
1✔
1293
                ("ints", FeatureData::Int(vec![1, 2, 3])),
1✔
1294
                (
1✔
1295
                    "floats",
1✔
1296
                    FeatureData::NullableFloat(vec![Some(1.0), None, Some(3.0)]),
1✔
1297
                ),
1✔
1298
                (
1✔
1299
                    "texts",
1✔
1300
                    FeatureData::NullableText(vec![
1✔
1301
                        Some("a".to_owned()),
1✔
1302
                        Some("b".to_owned()),
1✔
1303
                        None,
1✔
1304
                    ]),
1✔
1305
                ),
1✔
1306
                (
1✔
1307
                    "bools",
1✔
1308
                    FeatureData::NullableBool(vec![Some(true), Some(false), None]),
1✔
1309
                ),
1✔
1310
                (
1✔
1311
                    "dates",
1✔
1312
                    FeatureData::NullableDateTime(vec![
1✔
1313
                        Some(TimeInstance::from_millis_unchecked(946_681_200_000)),
1✔
1314
                        None,
1✔
1315
                        Some(TimeInstance::from_millis_unchecked(1_636_448_729_000)),
1✔
1316
                    ]),
1✔
1317
                ),
1✔
1318
            ],
1✔
1319
        )
1✔
1320
        .unwrap();
1✔
1321

1✔
1322
        let from_ints: Vec<String> = collection.data("ints").unwrap().strings_iter().collect();
1✔
1323
        let from_ints_cmp: Vec<String> = ["1", "2", "3"].iter().map(ToString::to_string).collect();
1✔
1324
        assert_eq!(from_ints, from_ints_cmp);
1✔
1325

1326
        let from_floats: Vec<String> = collection.data("floats").unwrap().strings_iter().collect();
1✔
1327
        let from_floats_cmp: Vec<String> = ["1", "", "3"].iter().map(ToString::to_string).collect();
1✔
1328
        assert_eq!(from_floats, from_floats_cmp);
1✔
1329

1330
        let from_strings: Vec<String> = collection.data("texts").unwrap().strings_iter().collect();
1✔
1331
        let from_strings_cmp: Vec<String> =
1✔
1332
            ["a", "b", ""].iter().map(ToString::to_string).collect();
1✔
1333
        assert_eq!(from_strings, from_strings_cmp);
1✔
1334

1335
        let from_bools: Vec<String> = collection.data("bools").unwrap().strings_iter().collect();
1✔
1336
        let from_bools_cmp: Vec<String> = ["true", "false", ""]
1✔
1337
            .iter()
1✔
1338
            .map(ToString::to_string)
1✔
1339
            .collect();
1✔
1340
        assert_eq!(from_bools, from_bools_cmp);
1✔
1341

1342
        let from_dates: Vec<String> = collection.data("dates").unwrap().strings_iter().collect();
1✔
1343
        let from_dates_cmp: Vec<String> =
1✔
1344
            ["1999-12-31T23:00:00.000Z", "", "2021-11-09T09:05:29.000Z"]
1✔
1345
                .iter()
1✔
1346
                .map(ToString::to_string)
1✔
1347
                .collect();
1✔
1348
        assert_eq!(from_dates, from_dates_cmp);
1✔
1349
    }
1✔
1350

1351
    #[test]
1✔
1352
    fn float_options_iter() {
1✔
1353
        let collection = DataCollection::from_slices(
1✔
1354
            &[] as &[NoGeometry],
1✔
1355
            &[TimeInterval::default(); 3],
1✔
1356
            &[
1✔
1357
                ("ints", FeatureData::Int(vec![1, 2, 3])),
1✔
1358
                (
1✔
1359
                    "floats",
1✔
1360
                    FeatureData::NullableFloat(vec![Some(1.0), None, Some(3.0)]),
1✔
1361
                ),
1✔
1362
                (
1✔
1363
                    "texts",
1✔
1364
                    FeatureData::NullableText(vec![
1✔
1365
                        Some("1".to_owned()),
1✔
1366
                        Some("f".to_owned()),
1✔
1367
                        None,
1✔
1368
                    ]),
1✔
1369
                ),
1✔
1370
                (
1✔
1371
                    "bools",
1✔
1372
                    FeatureData::NullableBool(vec![Some(true), Some(false), None]),
1✔
1373
                ),
1✔
1374
                (
1✔
1375
                    "dates",
1✔
1376
                    FeatureData::NullableDateTime(vec![
1✔
1377
                        Some(TimeInstance::from_millis_unchecked(946_681_200_000)),
1✔
1378
                        None,
1✔
1379
                        Some(TimeInstance::from_millis_unchecked(1_636_448_729_000)),
1✔
1380
                    ]),
1✔
1381
                ),
1✔
1382
            ],
1✔
1383
        )
1✔
1384
        .unwrap();
1✔
1385

1✔
1386
        let from_ints: Vec<Option<f64>> = collection
1✔
1387
            .data("ints")
1✔
1388
            .unwrap()
1✔
1389
            .float_options_iter()
1✔
1390
            .collect();
1✔
1391
        let from_ints_cmp: Vec<Option<f64>> = vec![Some(1.0), Some(2.0), Some(3.0)];
1✔
1392
        assert_eq!(from_ints, from_ints_cmp);
1✔
1393

1394
        let from_floats: Vec<Option<f64>> = collection
1✔
1395
            .data("floats")
1✔
1396
            .unwrap()
1✔
1397
            .float_options_iter()
1✔
1398
            .collect();
1✔
1399
        let from_floats_cmp: Vec<Option<f64>> = vec![Some(1.0), None, Some(3.0)];
1✔
1400
        assert_eq!(from_floats, from_floats_cmp);
1✔
1401

1402
        let from_strings: Vec<Option<f64>> = collection
1✔
1403
            .data("texts")
1✔
1404
            .unwrap()
1✔
1405
            .float_options_iter()
1✔
1406
            .collect();
1✔
1407
        let from_strings_cmp: Vec<Option<f64>> = vec![Some(1.0), None, None];
1✔
1408
        assert_eq!(from_strings, from_strings_cmp);
1✔
1409

1410
        let from_bools: Vec<Option<f64>> = collection
1✔
1411
            .data("bools")
1✔
1412
            .unwrap()
1✔
1413
            .float_options_iter()
1✔
1414
            .collect();
1✔
1415
        let from_bools_cmp: Vec<Option<f64>> = vec![Some(1.0), Some(0.0), None];
1✔
1416
        assert_eq!(from_bools, from_bools_cmp);
1✔
1417

1418
        let from_dates: Vec<Option<f64>> = collection
1✔
1419
            .data("dates")
1✔
1420
            .unwrap()
1✔
1421
            .float_options_iter()
1✔
1422
            .collect();
1✔
1423
        let from_dates_cmp: Vec<Option<f64>> =
1✔
1424
            vec![Some(946_681_200_000.0), None, Some(1_636_448_729_000.0)];
1✔
1425
        assert_eq!(from_dates, from_dates_cmp);
1✔
1426
    }
1✔
1427
}
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