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

geo-engine / geoengine / 5641674846

24 Jul 2023 06:42AM UTC coverage: 88.938% (-0.2%) from 89.184%
5641674846

Pull #833

github

web-flow
Merge 054f347f4 into 8c287ecf7
Pull Request #833: Shared-cache

1301 of 1301 new or added lines in 15 files covered. (100.0%)

105810 of 118970 relevant lines covered (88.94%)

60854.04 hits per line

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

92.5
/datatypes/src/primitives/multi_line_string.rs
1
use std::convert::TryFrom;
2

3
use arrow::array::BooleanArray;
4
use arrow::error::ArrowError;
5
use float_cmp::{ApproxEq, F64Margin};
6
use geo::algorithm::intersects::Intersects;
7
use serde::{Deserialize, Serialize};
8
use snafu::ensure;
9
use wkt::{ToWkt, Wkt};
10

11
use crate::collections::VectorDataType;
12
use crate::error::Error;
13
use crate::primitives::{
14
    error, BoundingBox2D, GeometryRef, MultiPoint, PrimitivesError, TypedGeometry,
15
};
16
use crate::primitives::{Coordinate2D, Geometry};
17
use crate::util::arrow::{downcast_array, padded_buffer_size, ArrowTyped};
18
use crate::util::Result;
19

20
/// A trait that allows a common access to lines of `MultiLineString`s and its references
21
pub trait MultiLineStringAccess {
22
    type L: AsRef<[Coordinate2D]>;
23
    fn lines(&self) -> &[Self::L];
24
}
25

26
/// A representation of a simple feature multi line string
27
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
10✔
28
pub struct MultiLineString {
29
    coordinates: Vec<Vec<Coordinate2D>>,
30
}
31

32
impl MultiLineString {
33
    pub fn new(coordinates: Vec<Vec<Coordinate2D>>) -> Result<Self> {
4,078✔
34
        ensure!(
4,078✔
35
            !coordinates.is_empty() && coordinates.iter().all(|c| c.len() >= 2),
10,830✔
36
            error::UnallowedEmpty
×
37
        );
38

39
        Ok(Self::new_unchecked(coordinates))
4,078✔
40
    }
4,078✔
41

42
    pub(crate) fn new_unchecked(coordinates: Vec<Vec<Coordinate2D>>) -> Self {
4,088✔
43
        Self { coordinates }
4,088✔
44
    }
4,088✔
45
}
46

47
impl MultiLineStringAccess for MultiLineString {
48
    type L = Vec<Coordinate2D>;
49
    fn lines(&self) -> &[Vec<Coordinate2D>] {
4,077✔
50
        &self.coordinates
4,077✔
51
    }
4,077✔
52
}
53

54
impl Geometry for MultiLineString {
55
    const DATA_TYPE: VectorDataType = VectorDataType::MultiLineString;
56

57
    fn intersects_bbox(&self, bbox: &BoundingBox2D) -> bool {
×
58
        let geo::MultiLineString::<f64>(geo_line_strings) = self.into();
×
59
        let geo_rect: geo::Rect<f64> = bbox.into();
×
60

61
        for line_string in geo_line_strings {
×
62
            for line in line_string.lines() {
×
63
                if line.intersects(&geo_rect) {
×
64
                    return true;
×
65
                }
×
66
            }
67
        }
68

69
        false
×
70
    }
×
71
}
72

73
impl From<&MultiLineString> for geo::MultiLineString<f64> {
74
    fn from(geometry: &MultiLineString) -> geo::MultiLineString<f64> {
1✔
75
        let line_strings = geometry
1✔
76
            .coordinates
1✔
77
            .iter()
1✔
78
            .map(|coordinates| {
3✔
79
                let geo_coordinates = coordinates.iter().map(Into::into).collect();
3✔
80
                geo::LineString(geo_coordinates)
3✔
81
            })
3✔
82
            .collect();
1✔
83
        geo::MultiLineString(line_strings)
1✔
84
    }
1✔
85
}
86

87
impl From<geo::MultiLineString<f64>> for MultiLineString {
88
    fn from(geo_geometry: geo::MultiLineString<f64>) -> MultiLineString {
3✔
89
        let coordinates = geo_geometry
3✔
90
            .0
3✔
91
            .into_iter()
3✔
92
            .map(|geo_line_string| {
5✔
93
                geo_line_string
5✔
94
                    .0
5✔
95
                    .into_iter()
5✔
96
                    .map(Into::into)
5✔
97
                    .collect::<Vec<_>>()
5✔
98
            })
5✔
99
            .collect();
3✔
100
        MultiLineString::new_unchecked(coordinates)
3✔
101
    }
3✔
102
}
103

104
impl TryFrom<TypedGeometry> for MultiLineString {
105
    type Error = Error;
106

107
    fn try_from(value: TypedGeometry) -> Result<Self, Self::Error> {
108
        if let TypedGeometry::MultiLineString(geometry) = value {
×
109
            Ok(geometry)
×
110
        } else {
111
            Err(PrimitivesError::InvalidConversion.into())
×
112
        }
113
    }
×
114
}
115

116
impl AsRef<[Vec<Coordinate2D>]> for MultiLineString {
117
    fn as_ref(&self) -> &[Vec<Coordinate2D>] {
19✔
118
        &self.coordinates
19✔
119
    }
19✔
120
}
121

122
impl ApproxEq for &MultiLineString {
123
    type Margin = F64Margin;
124

125
    fn approx_eq<M: Into<Self::Margin>>(self, other: Self, margin: M) -> bool {
6✔
126
        let m = margin.into();
6✔
127
        self.lines().len() == other.lines().len()
6✔
128
            && self
5✔
129
                .lines()
5✔
130
                .iter()
5✔
131
                .zip(other.lines().iter())
5✔
132
                .all(|(line_a, line_b)| line_a.len() == line_b.len() && line_a.approx_eq(line_b, m))
9✔
133
    }
6✔
134
}
135

136
impl ArrowTyped for MultiLineString {
137
    type ArrowArray = arrow::array::ListArray;
138
    type ArrowBuilder = arrow::array::ListBuilder<
139
        arrow::array::ListBuilder<<Coordinate2D as ArrowTyped>::ArrowBuilder>,
140
    >;
141

142
    fn arrow_data_type() -> arrow::datatypes::DataType {
78✔
143
        MultiPoint::arrow_list_data_type()
78✔
144
    }
78✔
145

146
    fn estimate_array_memory_size(builder: &mut Self::ArrowBuilder) -> usize {
128✔
147
        let static_size = std::mem::size_of::<Self::ArrowArray>()
128✔
148
            + std::mem::size_of::<<MultiPoint as ArrowTyped>::ArrowArray>();
128✔
149

128✔
150
        let feature_offset_bytes_size = std::mem::size_of_val(builder.offsets_slice());
128✔
151

128✔
152
        let line_builder = builder.values();
128✔
153

128✔
154
        let line_offset_bytes_size = std::mem::size_of_val(line_builder.offsets_slice());
128✔
155

128✔
156
        let coordinates_builder = line_builder.values();
128✔
157

128✔
158
        let coords_size = Coordinate2D::estimate_array_memory_size(coordinates_builder);
128✔
159

128✔
160
        static_size
128✔
161
            + coords_size
128✔
162
            + padded_buffer_size(line_offset_bytes_size, 64)
128✔
163
            + padded_buffer_size(feature_offset_bytes_size, 64)
128✔
164
    }
128✔
165

166
    fn arrow_builder(capacity: usize) -> Self::ArrowBuilder {
149✔
167
        let minimal_number_of_coordinates = 2 * capacity; // at least 2 coordinates per line string
149✔
168
        let coordinate_builder = Coordinate2D::arrow_builder(minimal_number_of_coordinates);
149✔
169
        let line_string_builder = arrow::array::ListBuilder::new(coordinate_builder);
149✔
170
        arrow::array::ListBuilder::new(line_string_builder) // multi line strings = lists of line strings
149✔
171
    }
149✔
172

173
    fn concat(a: &Self::ArrowArray, b: &Self::ArrowArray) -> Result<Self::ArrowArray, ArrowError> {
1✔
174
        use arrow::array::{Array, FixedSizeListArray, Float64Array, ListArray};
1✔
175

1✔
176
        let mut multi_line_builder = Self::arrow_builder(a.len() + b.len());
1✔
177

178
        for multi_lines in &[a, b] {
2✔
179
            for multi_line_index in 0..multi_lines.len() {
2✔
180
                let line_builder = multi_line_builder.values();
2✔
181

2✔
182
                let lines_ref = multi_lines.value(multi_line_index);
2✔
183
                let lines = downcast_array::<ListArray>(&lines_ref);
2✔
184

185
                for line_index in 0..lines.len() {
3✔
186
                    let coordinate_builder = line_builder.values();
3✔
187

3✔
188
                    let coordinates_ref = lines.value(line_index);
3✔
189
                    let coordinates = downcast_array::<FixedSizeListArray>(&coordinates_ref);
3✔
190

191
                    for coordinate_index in 0..coordinates.len() {
8✔
192
                        let floats_ref = coordinates.value(coordinate_index);
8✔
193
                        let floats: &Float64Array = downcast_array(&floats_ref);
8✔
194

8✔
195
                        coordinate_builder.values().append_slice(floats.values());
8✔
196

8✔
197
                        coordinate_builder.append(true);
8✔
198
                    }
8✔
199

200
                    line_builder.append(true);
3✔
201
                }
202

203
                multi_line_builder.append(true);
2✔
204
            }
205
        }
206

207
        Ok(multi_line_builder.finish_cloned())
1✔
208
    }
1✔
209

210
    fn filter(
4✔
211
        multi_lines: &Self::ArrowArray,
4✔
212
        filter_array: &BooleanArray,
4✔
213
    ) -> Result<Self::ArrowArray, ArrowError> {
4✔
214
        use arrow::array::{Array, FixedSizeListArray, Float64Array, ListArray};
4✔
215

4✔
216
        let mut multi_line_builder = Self::arrow_builder(0);
4✔
217

218
        for multi_line_index in 0..multi_lines.len() {
8✔
219
            if !filter_array.value(multi_line_index) {
8✔
220
                continue;
2✔
221
            }
6✔
222

6✔
223
            let line_builder = multi_line_builder.values();
6✔
224

6✔
225
            let lines_ref = multi_lines.value(multi_line_index);
6✔
226
            let lines = downcast_array::<ListArray>(&lines_ref);
6✔
227

228
            for line_index in 0..lines.len() {
7✔
229
                let coordinate_builder = line_builder.values();
7✔
230

7✔
231
                let coordinates_ref = lines.value(line_index);
7✔
232
                let coordinates = downcast_array::<FixedSizeListArray>(&coordinates_ref);
7✔
233

234
                for coordinate_index in 0..coordinates.len() {
19✔
235
                    let floats_ref = coordinates.value(coordinate_index);
19✔
236
                    let floats: &Float64Array = downcast_array(&floats_ref);
19✔
237

19✔
238
                    coordinate_builder.values().append_slice(floats.values());
19✔
239

19✔
240
                    coordinate_builder.append(true);
19✔
241
                }
19✔
242

243
                line_builder.append(true);
7✔
244
            }
245

246
            multi_line_builder.append(true);
6✔
247
        }
248

249
        Ok(multi_line_builder.finish_cloned())
4✔
250
    }
4✔
251

252
    fn from_vec(multi_line_strings: Vec<Self>) -> Result<Self::ArrowArray, ArrowError>
10✔
253
    where
10✔
254
        Self: Sized,
10✔
255
    {
10✔
256
        let mut builder = Self::arrow_builder(multi_line_strings.len());
10✔
257
        for multi_line_string in multi_line_strings {
29✔
258
            let line_string_builder = builder.values();
19✔
259

260
            for line_string in multi_line_string.as_ref() {
25✔
261
                let coordinate_builder = line_string_builder.values();
25✔
262

263
                for coordinate in line_string {
89✔
264
                    let float_builder = coordinate_builder.values();
64✔
265
                    float_builder.append_value(coordinate.x);
64✔
266
                    float_builder.append_value(coordinate.y);
64✔
267
                    coordinate_builder.append(true);
64✔
268
                }
64✔
269

270
                line_string_builder.append(true);
25✔
271
            }
272

273
            builder.append(true);
19✔
274
        }
275

276
        Ok(builder.finish_cloned())
10✔
277
    }
10✔
278
}
279

280
#[derive(Debug, PartialEq)]
×
281
pub struct MultiLineStringRef<'g> {
282
    point_coordinates: Vec<&'g [Coordinate2D]>,
283
}
284

285
impl<'r> GeometryRef for MultiLineStringRef<'r> {
286
    type GeometryType = MultiLineString;
287

288
    fn as_geometry(&self) -> Self::GeometryType {
×
289
        self.into()
×
290
    }
×
291

292
    fn bbox(&self) -> Option<BoundingBox2D> {
×
293
        self.bbox()
×
294
    }
×
295
}
296

297
impl<'g> MultiLineStringRef<'g> {
298
    pub fn new(coordinates: Vec<&'g [Coordinate2D]>) -> Result<Self> {
1✔
299
        ensure!(!coordinates.is_empty(), error::UnallowedEmpty);
1✔
300

301
        Ok(Self::new_unchecked(coordinates))
1✔
302
    }
1✔
303

304
    pub(crate) fn new_unchecked(coordinates: Vec<&'g [Coordinate2D]>) -> Self {
25✔
305
        Self {
25✔
306
            point_coordinates: coordinates,
25✔
307
        }
25✔
308
    }
25✔
309

310
    pub fn bbox(&self) -> Option<BoundingBox2D> {
×
311
        self.lines().iter().fold(None, |bbox, line| {
×
312
            let lbox = BoundingBox2D::from_coord_ref_iter(line.iter());
×
313
            match (bbox, lbox) {
×
314
                (None, Some(lbox)) => Some(lbox),
×
315
                (Some(bbox), Some(lbox)) => Some(bbox.union(&lbox)),
×
316
                (bbox, None) => bbox,
×
317
            }
318
        })
×
319
    }
×
320
}
321

322
impl<'g> MultiLineStringAccess for MultiLineStringRef<'g> {
323
    type L = &'g [Coordinate2D];
324
    fn lines(&self) -> &[&'g [Coordinate2D]] {
13✔
325
        &self.point_coordinates
13✔
326
    }
13✔
327
}
328

329
impl<'r> ToWkt<f64> for MultiLineStringRef<'r> {
330
    fn to_wkt(&self) -> Wkt<f64> {
1✔
331
        let line_strings = self.lines();
1✔
332
        let mut multi_line_string =
1✔
333
            wkt::types::MultiLineString(Vec::with_capacity(line_strings.len()));
1✔
334

335
        for line_string in line_strings {
4✔
336
            let mut line_strings = wkt::types::LineString(Vec::with_capacity(line_string.len()));
3✔
337

338
            for coord in *line_string {
10✔
339
                line_strings.0.push(coord.into());
7✔
340
            }
7✔
341

342
            multi_line_string.0.push(line_strings);
3✔
343
        }
344

345
        Wkt {
1✔
346
            item: wkt::Geometry::MultiLineString(multi_line_string),
1✔
347
        }
1✔
348
    }
1✔
349
}
350

351
impl<'g> From<MultiLineStringRef<'g>> for geojson::Geometry {
352
    fn from(geometry: MultiLineStringRef<'g>) -> geojson::Geometry {
2✔
353
        geojson::Geometry::new(match geometry.point_coordinates.len() {
2✔
354
            1 => {
355
                let coordinates = geometry.point_coordinates[0];
1✔
356
                let positions = coordinates.iter().map(|c| vec![c.x, c.y]).collect();
3✔
357
                geojson::Value::LineString(positions)
1✔
358
            }
359
            _ => geojson::Value::MultiLineString(
1✔
360
                geometry
1✔
361
                    .point_coordinates
1✔
362
                    .iter()
1✔
363
                    .map(|&coordinates| coordinates.iter().map(|c| vec![c.x, c.y]).collect())
5✔
364
                    .collect(),
1✔
365
            ),
1✔
366
        })
367
    }
2✔
368
}
369

370
impl<'g> From<MultiLineStringRef<'g>> for MultiLineString {
371
    fn from(multi_line_string_ref: MultiLineStringRef<'g>) -> Self {
7✔
372
        MultiLineString::from(&multi_line_string_ref)
7✔
373
    }
7✔
374
}
375

376
impl<'g> From<&MultiLineStringRef<'g>> for MultiLineString {
377
    fn from(multi_line_string_ref: &MultiLineStringRef<'g>) -> Self {
7✔
378
        MultiLineString::new_unchecked(
7✔
379
            multi_line_string_ref
7✔
380
                .point_coordinates
7✔
381
                .iter()
7✔
382
                .copied()
7✔
383
                .map(ToOwned::to_owned)
7✔
384
                .collect(),
7✔
385
        )
7✔
386
    }
7✔
387
}
388

389
impl<'g> From<&'g MultiLineString> for MultiLineStringRef<'g> {
390
    fn from(multi_line_string: &'g MultiLineString) -> Self {
1✔
391
        MultiLineStringRef::new_unchecked(
1✔
392
            multi_line_string
1✔
393
                .lines()
1✔
394
                .iter()
1✔
395
                .map(AsRef::as_ref)
1✔
396
                .collect::<Vec<_>>(),
1✔
397
        )
1✔
398
    }
1✔
399
}
400

401
impl<'g> From<&MultiLineStringRef<'g>> for geo::MultiLineString<f64> {
402
    fn from(geometry: &MultiLineStringRef<'g>) -> Self {
2✔
403
        let line_strings = geometry
2✔
404
            .point_coordinates
2✔
405
            .iter()
2✔
406
            .map(|coordinates| {
2✔
407
                let geo_coordinates = coordinates.iter().map(Into::into).collect();
2✔
408
                geo::LineString(geo_coordinates)
2✔
409
            })
2✔
410
            .collect();
2✔
411
        geo::MultiLineString(line_strings)
2✔
412
    }
2✔
413
}
414

415
#[cfg(test)]
416
mod tests {
417
    use super::*;
418
    use arrow::array::{Array, ArrayBuilder};
419
    use float_cmp::approx_eq;
420

421
    #[test]
1✔
422
    fn access() {
1✔
423
        fn aggregate<T: MultiLineStringAccess>(multi_line_string: &T) -> (usize, usize) {
3✔
424
            let number_of_lines = multi_line_string.lines().len();
3✔
425
            let number_of_coordinates = multi_line_string
3✔
426
                .lines()
3✔
427
                .iter()
3✔
428
                .map(AsRef::as_ref)
3✔
429
                .map(<[Coordinate2D]>::len)
3✔
430
                .sum();
3✔
431

3✔
432
            (number_of_lines, number_of_coordinates)
3✔
433
        }
3✔
434

1✔
435
        let coordinates = vec![
1✔
436
            vec![(0.0, 0.1).into(), (1.0, 1.1).into()],
1✔
437
            vec![(3.0, 3.1).into(), (4.0, 4.1).into()],
1✔
438
        ];
1✔
439
        let multi_line_string = MultiLineString::new(coordinates.clone()).unwrap();
1✔
440
        let multi_line_string_ref =
1✔
441
            MultiLineStringRef::new(coordinates.iter().map(AsRef::as_ref).collect()).unwrap();
1✔
442

1✔
443
        assert_eq!(aggregate(&multi_line_string), (2, 4));
1✔
444
        assert_eq!(
1✔
445
            aggregate(&multi_line_string),
1✔
446
            aggregate(&multi_line_string_ref)
1✔
447
        );
1✔
448
    }
1✔
449

450
    #[test]
1✔
451
    fn approx_equal() {
1✔
452
        let a = MultiLineString::new(vec![
1✔
453
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
454
            vec![(0.5, 0.5).into(), (0.6, 0.6).into()],
1✔
455
            vec![(0.6, 0.6).into(), (0.9, 0.9).into()],
1✔
456
        ])
1✔
457
        .unwrap();
1✔
458

1✔
459
        let b = MultiLineString::new(vec![
1✔
460
            vec![(0.099_999_999, 0.1).into(), (0.5, 0.5).into()],
1✔
461
            vec![(0.5, 0.5).into(), (0.6, 0.6).into()],
1✔
462
            vec![(0.6, 0.6).into(), (0.9, 0.9).into()],
1✔
463
        ])
1✔
464
        .unwrap();
1✔
465

1✔
466
        assert!(approx_eq!(&MultiLineString, &a, &b, epsilon = 0.000_001));
1✔
467
    }
1✔
468

469
    #[test]
1✔
470
    fn not_approx_equal_outer_len() {
1✔
471
        let a = MultiLineString::new(vec![
1✔
472
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
473
            vec![(0.5, 0.5).into(), (0.6, 0.6).into()],
1✔
474
            vec![(0.6, 0.6).into(), (0.9, 0.9).into()],
1✔
475
        ])
1✔
476
        .unwrap();
1✔
477

1✔
478
        let b = MultiLineString::new(vec![
1✔
479
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
480
            vec![(0.5, 0.5).into(), (0.6, 0.6).into()],
1✔
481
            vec![(0.6, 0.6).into(), (0.9, 0.9).into()],
1✔
482
            vec![(0.9, 0.9).into(), (123_456_789.9, 123_456_789.9).into()],
1✔
483
        ])
1✔
484
        .unwrap();
1✔
485

1✔
486
        assert!(!approx_eq!(&MultiLineString, &a, &b, F64Margin::default()));
1✔
487
    }
1✔
488

489
    #[test]
1✔
490
    fn not_approx_equal_inner_len() {
1✔
491
        let a = MultiLineString::new(vec![
1✔
492
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
493
            vec![(0.5, 0.5).into(), (0.6, 0.6).into(), (0.7, 0.7).into()],
1✔
494
            vec![(0.7, 0.7).into(), (0.9, 0.9).into()],
1✔
495
        ])
1✔
496
        .unwrap();
1✔
497

1✔
498
        let b = MultiLineString::new(vec![
1✔
499
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
500
            vec![(0.5, 0.5).into(), (0.6, 0.6).into()],
1✔
501
            vec![(0.6, 0.6).into(), (0.7, 0.7).into(), (0.9, 0.9).into()],
1✔
502
        ])
1✔
503
        .unwrap();
1✔
504

1✔
505
        assert!(!approx_eq!(&MultiLineString, &a, &b, F64Margin::default()));
1✔
506
    }
1✔
507

508
    #[test]
1✔
509
    fn test_to_wkt() {
1✔
510
        let a = MultiLineString::new(vec![
1✔
511
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
512
            vec![(0.5, 0.5).into(), (0.6, 0.6).into(), (0.7, 0.7).into()],
1✔
513
            vec![(0.7, 0.7).into(), (0.9, 0.9).into()],
1✔
514
        ])
1✔
515
        .unwrap();
1✔
516

1✔
517
        let a_ref = MultiLineStringRef::from(&a);
1✔
518

1✔
519
        assert_eq!(
1✔
520
            a_ref.wkt_string(),
1✔
521
            "MULTILINESTRING((0.1 0.1,0.5 0.5),(0.5 0.5,0.6 0.6,0.7 0.7),(0.7 0.7,0.9 0.9))"
1✔
522
        );
1✔
523
    }
1✔
524

525
    #[test]
1✔
526
    fn test_to_geo_and_back() {
1✔
527
        let line_string = MultiLineString::new(vec![
1✔
528
            vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1✔
529
            vec![(0.5, 0.5).into(), (0.6, 0.6).into(), (0.7, 0.7).into()],
1✔
530
            vec![(0.7, 0.7).into(), (0.9, 0.9).into()],
1✔
531
        ])
1✔
532
        .unwrap();
1✔
533

1✔
534
        let geo_line_string = geo::MultiLineString::<f64>::from(&line_string);
1✔
535

1✔
536
        let line_string_back = MultiLineString::from(geo_line_string);
1✔
537

1✔
538
        assert_eq!(line_string, line_string_back);
1✔
539
    }
1✔
540

541
    #[test]
1✔
542
    fn arrow_builder_size() {
1✔
543
        fn push_geometry(
4,032✔
544
            geometries_builder: &mut <MultiLineString as ArrowTyped>::ArrowBuilder,
4,032✔
545
            geometry: &MultiLineString,
4,032✔
546
        ) {
4,032✔
547
            let line_builder = geometries_builder.values();
4,032✔
548

549
            for line in geometry.lines() {
10,752✔
550
                let coordinate_builder = line_builder.values();
10,752✔
551

552
                for coordinate in line {
33,558✔
553
                    coordinate_builder
22,806✔
554
                        .values()
22,806✔
555
                        .append_slice(coordinate.as_ref());
22,806✔
556

22,806✔
557
                    coordinate_builder.append(true);
22,806✔
558
                }
22,806✔
559

560
                line_builder.append(true);
10,752✔
561
            }
562

563
            geometries_builder.append(true);
4,032✔
564
        }
4,032✔
565

566
        for num_multi_lines in 0..64 {
65✔
567
            for capacity in [0, num_multi_lines] {
128✔
568
                let mut builder = MultiLineString::arrow_builder(capacity);
128✔
569

570
                for i in 0..num_multi_lines {
4,032✔
571
                    match i % 3 {
4,032✔
572
                        0 => {
1,386✔
573
                            push_geometry(
1,386✔
574
                                &mut builder,
1,386✔
575
                                &MultiLineString::new(vec![
1,386✔
576
                                    vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1,386✔
577
                                    vec![(0.5, 0.5).into(), (0.6, 0.6).into()],
1,386✔
578
                                    vec![(0.6, 0.6).into(), (0.9, 0.9).into()],
1,386✔
579
                                ])
1,386✔
580
                                .unwrap(),
1,386✔
581
                            );
1,386✔
582
                        }
1,386✔
583
                        1 => {
1,344✔
584
                            push_geometry(
1,344✔
585
                                &mut builder,
1,344✔
586
                                &MultiLineString::new(vec![
1,344✔
587
                                    vec![(0.0, 0.1).into(), (1.0, 1.1).into()],
1,344✔
588
                                    vec![(3.0, 3.1).into(), (4.0, 4.1).into()],
1,344✔
589
                                ])
1,344✔
590
                                .unwrap(),
1,344✔
591
                            );
1,344✔
592
                        }
1,344✔
593
                        2 => {
1,302✔
594
                            push_geometry(
1,302✔
595
                                &mut builder,
1,302✔
596
                                &MultiLineString::new(vec![
1,302✔
597
                                    vec![(0.1, 0.1).into(), (0.5, 0.5).into()],
1,302✔
598
                                    vec![(0.5, 0.5).into(), (0.6, 0.6).into(), (0.7, 0.7).into()],
1,302✔
599
                                    vec![(0.7, 0.7).into(), (0.9, 0.9).into()],
1,302✔
600
                                ])
1,302✔
601
                                .unwrap(),
1,302✔
602
                            );
1,302✔
603
                        }
1,302✔
604
                        _ => unreachable!(),
×
605
                    }
606
                }
607

608
                assert_eq!(builder.len(), num_multi_lines);
128✔
609

610
                let builder_byte_size = MultiLineString::estimate_array_memory_size(&mut builder);
128✔
611

128✔
612
                let array = builder.finish_cloned();
128✔
613

128✔
614
                assert_eq!(
128✔
615
                    builder_byte_size,
128✔
616
                    array.get_array_memory_size(),
128✔
617
                    "{num_multi_lines}"
×
618
                );
619
            }
620
        }
621
    }
1✔
622
}
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