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

geo-engine / geoengine / 12864373935

20 Jan 2025 08:57AM UTC coverage: 90.007% (-0.6%) from 90.64%
12864373935

Pull #1008

github

web-flow
Merge 7d012d0a9 into de81b44f7
Pull Request #1008: user ctx in ge_test

3691 of 3793 new or added lines in 64 files covered. (97.31%)

786 existing lines in 19 files now uncovered.

127380 of 141522 relevant lines covered (90.01%)

56878.96 hits per line

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

83.67
/datatypes/src/primitives/multi_point.rs
1
use super::SpatialBounded;
2
use crate::collections::VectorDataType;
3
use crate::error::Error;
4
use crate::primitives::{error, BoundingBox2D, GeometryRef, PrimitivesError, TypedGeometry};
5
use crate::primitives::{Coordinate2D, Geometry};
6
use crate::util::arrow::{downcast_array, padded_buffer_size, ArrowTyped};
7
use crate::util::Result;
8
use arrow::array::{BooleanArray, FixedSizeListArray, Float64Array};
9
use arrow::error::ArrowError;
10
use fallible_iterator::FallibleIterator;
11
use float_cmp::{ApproxEq, F64Margin};
12
use postgres_types::{FromSql, ToSql};
13
use proj::Coord;
14
use serde::{Deserialize, Serialize};
15
use snafu::ensure;
16
use std::convert::{TryFrom, TryInto};
17
use wkt::{ToWkt, Wkt};
18

19
/// A trait that allows a common access to points of `MultiPoint`s and its references
20
pub trait MultiPointAccess {
21
    fn points(&self) -> &[Coordinate2D];
22
}
23

24
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
25
pub struct MultiPoint {
26
    coordinates: Vec<Coordinate2D>,
27
}
28

29
impl MultiPoint {
30
    pub fn new(coordinates: Vec<Coordinate2D>) -> Result<Self> {
7,978✔
31
        ensure!(!coordinates.is_empty(), error::UnallowedEmpty);
7,978✔
32

33
        Ok(Self::new_unchecked(coordinates))
7,978✔
34
    }
7,978✔
35

36
    pub(crate) fn new_unchecked(coordinates: Vec<Coordinate2D>) -> Self {
9,787✔
37
        Self { coordinates }
9,787✔
38
    }
9,787✔
39

40
    pub fn many<M, E>(raw_multi_points: Vec<M>) -> Result<Vec<Self>>
132✔
41
    where
132✔
42
        M: TryInto<MultiPoint, Error = E>,
132✔
43
        E: Into<crate::error::Error>,
132✔
44
    {
132✔
45
        raw_multi_points
132✔
46
            .into_iter()
132✔
47
            .map(|m| m.try_into().map_err(Into::into))
1,693✔
48
            .collect()
132✔
49
    }
132✔
50
}
51

52
impl MultiPointAccess for MultiPoint {
53
    fn points(&self) -> &[Coordinate2D] {
115✔
54
        &self.coordinates
115✔
55
    }
115✔
56
}
57

58
impl Geometry for MultiPoint {
59
    const DATA_TYPE: VectorDataType = VectorDataType::MultiPoint;
60

61
    fn intersects_bbox(&self, bbox: &BoundingBox2D) -> bool {
7,747✔
62
        self.coordinates.iter().any(|c| bbox.contains_coordinate(c))
7,748✔
63
    }
7,747✔
64
}
65

66
impl TryFrom<TypedGeometry> for MultiPoint {
67
    type Error = Error;
68

69
    fn try_from(value: TypedGeometry) -> Result<Self, Self::Error> {
4✔
70
        if let TypedGeometry::MultiPoint(geometry) = value {
4✔
71
            Ok(geometry)
4✔
72
        } else {
73
            Err(PrimitivesError::InvalidConversion.into())
×
74
        }
75
    }
4✔
76
}
77

78
impl AsRef<[Coordinate2D]> for MultiPoint {
79
    fn as_ref(&self) -> &[Coordinate2D] {
5,211✔
80
        &self.coordinates
5,211✔
81
    }
5,211✔
82
}
83

84
impl<C> From<C> for MultiPoint
85
where
86
    C: Into<Coordinate2D>,
87
{
88
    fn from(c: C) -> Self {
1,644✔
89
        Self::new_unchecked(vec![c.into()])
1,644✔
90
    }
1,644✔
91
}
92

93
impl From<&Coordinate2D> for MultiPoint {
94
    fn from(point: &Coordinate2D) -> Self {
58✔
95
        Self::new_unchecked(vec![*point])
58✔
96
    }
58✔
97
}
98

99
impl TryFrom<Vec<Coordinate2D>> for MultiPoint {
100
    type Error = crate::error::Error;
101

102
    fn try_from(coordinates: Vec<Coordinate2D>) -> Result<Self, Self::Error> {
6✔
103
        MultiPoint::new(coordinates)
6✔
104
    }
6✔
105
}
106

107
impl TryFrom<Vec<(f64, f64)>> for MultiPoint {
108
    type Error = crate::error::Error;
109

110
    fn try_from(coordinates: Vec<(f64, f64)>) -> Result<Self, Self::Error> {
81✔
111
        MultiPoint::new(coordinates.into_iter().map(Into::into).collect())
81✔
112
    }
81✔
113
}
114

115
impl<'g> From<&MultiPointRef<'g>> for geo::MultiPoint<f64> {
116
    fn from(geometry: &MultiPointRef<'g>) -> Self {
108✔
117
        let points: Vec<geo::Point<f64>> = geometry
108✔
118
            .point_coordinates
108✔
119
            .iter()
108✔
120
            .map(|coordinate| geo::Point::new(coordinate.x(), coordinate.y()))
108✔
121
            .collect();
108✔
122
        geo::MultiPoint(points)
108✔
123
    }
108✔
124
}
125

126
impl TryFrom<geo::MultiPoint<f64>> for MultiPoint {
127
    type Error = crate::error::Error;
128

129
    fn try_from(geometry: geo::MultiPoint<f64>) -> Result<Self> {
2✔
130
        let points = geometry.0;
2✔
131
        let coordinates = points
2✔
132
            .into_iter()
2✔
133
            .map(|point| Coordinate2D::new(point.x(), point.y()))
2✔
134
            .collect();
2✔
135
        MultiPoint::new(coordinates)
2✔
136
    }
2✔
137
}
138

139
impl ToSql for MultiPoint {
UNCOV
140
    fn to_sql(
×
UNCOV
141
        &self,
×
UNCOV
142
        ty: &postgres_types::Type,
×
UNCOV
143
        w: &mut bytes::BytesMut,
×
UNCOV
144
    ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Sync + Send>> {
×
UNCOV
145
        let postgres_types::Kind::Array(member_type) = ty.kind() else {
×
146
            panic!("expected array type");
×
147
        };
148

UNCOV
149
        let dimension = postgres_protocol::types::ArrayDimension {
×
UNCOV
150
            len: self.coordinates.len() as i32,
×
UNCOV
151
            lower_bound: 1, // arrays are one-indexed
×
UNCOV
152
        };
×
UNCOV
153

×
UNCOV
154
        postgres_protocol::types::array_to_sql(
×
UNCOV
155
            Some(dimension),
×
UNCOV
156
            member_type.oid(),
×
UNCOV
157
            self.coordinates.iter(),
×
UNCOV
158
            |c, w| {
×
UNCOV
159
                postgres_protocol::types::point_to_sql(c.x, c.y, w);
×
UNCOV
160

×
UNCOV
161
                Ok(postgres_protocol::IsNull::No)
×
UNCOV
162
            },
×
UNCOV
163
            w,
×
UNCOV
164
        )?;
×
165

UNCOV
166
        Ok(postgres_types::IsNull::No)
×
UNCOV
167
    }
×
168

UNCOV
169
    fn accepts(ty: &postgres_types::Type) -> bool {
×
UNCOV
170
        let postgres_types::Kind::Array(inner_type) = ty.kind() else {
×
171
            return false;
×
172
        };
173

UNCOV
174
        matches!(inner_type, &postgres_types::Type::POINT)
×
UNCOV
175
    }
×
176

177
    postgres_types::to_sql_checked!();
178
}
179

180
impl<'a> FromSql<'a> for MultiPoint {
UNCOV
181
    fn from_sql(
×
UNCOV
182
        _ty: &postgres_types::Type,
×
UNCOV
183
        raw: &'a [u8],
×
UNCOV
184
    ) -> Result<Self, Box<dyn std::error::Error + Sync + Send>> {
×
UNCOV
185
        let array = postgres_protocol::types::array_from_sql(raw)?;
×
UNCOV
186
        if array.dimensions().count()? > 1 {
×
187
            return Err("array contains too many dimensions".into());
×
UNCOV
188
        }
×
189

UNCOV
190
        let coordinates = array
×
UNCOV
191
            .values()
×
UNCOV
192
            .map(|raw| {
×
UNCOV
193
                let Some(raw) = raw else {
×
194
                    return Err("array contains NULL values".into());
×
195
                };
UNCOV
196
                let point = postgres_protocol::types::point_from_sql(raw)?;
×
UNCOV
197
                Ok(Coordinate2D {
×
UNCOV
198
                    x: point.x(),
×
UNCOV
199
                    y: point.y(),
×
UNCOV
200
                })
×
UNCOV
201
            })
×
UNCOV
202
            .collect()?;
×
203

UNCOV
204
        Ok(Self { coordinates })
×
UNCOV
205
    }
×
206

207
    fn accepts(ty: &postgres_types::Type) -> bool {
145✔
208
        let postgres_types::Kind::Array(inner_type) = ty.kind() else {
145✔
209
            return false;
×
210
        };
211

212
        matches!(inner_type, &postgres_types::Type::POINT)
145✔
213
    }
145✔
214
}
215

216
impl ArrowTyped for MultiPoint {
217
    type ArrowArray = arrow::array::ListArray;
218
    type ArrowBuilder = arrow::array::ListBuilder<<Coordinate2D as ArrowTyped>::ArrowBuilder>;
219

220
    fn arrow_data_type() -> arrow::datatypes::DataType {
719✔
221
        Coordinate2D::arrow_list_data_type()
719✔
222
    }
719✔
223

224
    fn estimate_array_memory_size(builder: &mut Self::ArrowBuilder) -> usize {
7,739✔
225
        let static_size = std::mem::size_of::<Self::ArrowArray>();
7,739✔
226

7,739✔
227
        let coords_size = Coordinate2D::estimate_array_memory_size(builder.values());
7,739✔
228

7,739✔
229
        let offset_bytes = builder.offsets_slice();
7,739✔
230
        let offset_bytes_size = std::mem::size_of_val(offset_bytes);
7,739✔
231

7,739✔
232
        static_size + coords_size + padded_buffer_size(offset_bytes_size, 64)
7,739✔
233
    }
7,739✔
234

235
    fn arrow_builder(capacity: usize) -> Self::ArrowBuilder {
2,734✔
236
        arrow::array::ListBuilder::new(Coordinate2D::arrow_builder(capacity))
2,734✔
237
    }
2,734✔
238

239
    fn concat(a: &Self::ArrowArray, b: &Self::ArrowArray) -> Result<Self::ArrowArray, ArrowError> {
13✔
240
        use arrow::array::Array;
241

242
        let mut new_multipoints = Self::arrow_builder(a.len() + b.len());
13✔
243

244
        for old_multipoints in &[a, b] {
26✔
245
            for multipoint_index in 0..old_multipoints.len() {
43✔
246
                let multipoint_ref = old_multipoints.value(multipoint_index);
43✔
247
                let multipoint: &FixedSizeListArray = downcast_array(&multipoint_ref);
43✔
248

43✔
249
                let new_points = new_multipoints.values();
43✔
250

251
                for point_index in 0..multipoint.len() {
47✔
252
                    let floats_ref = multipoint.value(point_index);
47✔
253
                    let floats: &Float64Array = downcast_array(&floats_ref);
47✔
254

47✔
255
                    let new_floats = new_points.values();
47✔
256
                    new_floats.append_slice(floats.values());
47✔
257

47✔
258
                    new_points.append(true);
47✔
259
                }
47✔
260

261
                new_multipoints.append(true);
43✔
262
            }
263
        }
264

265
        Ok(new_multipoints.finish_cloned())
13✔
266
    }
13✔
267

268
    fn filter(
83✔
269
        features: &Self::ArrowArray,
83✔
270
        filter_array: &BooleanArray,
83✔
271
    ) -> Result<Self::ArrowArray, ArrowError> {
83✔
272
        use arrow::array::Array;
273

274
        let mut new_features = Self::arrow_builder(0);
83✔
275

276
        for feature_index in 0..features.len() {
405✔
277
            if filter_array.value(feature_index) {
405✔
278
                let coordinate_builder = new_features.values();
339✔
279

339✔
280
                let old_coordinates = features.value(feature_index);
339✔
281

282
                for coordinate_index in 0..features.value_length(feature_index) {
347✔
283
                    let old_floats_array = downcast_array::<FixedSizeListArray>(&old_coordinates)
347✔
284
                        .value(coordinate_index as usize);
347✔
285

347✔
286
                    let old_floats: &Float64Array = downcast_array(&old_floats_array);
347✔
287

347✔
288
                    let float_builder = coordinate_builder.values();
347✔
289
                    float_builder.append_slice(old_floats.values());
347✔
290

347✔
291
                    coordinate_builder.append(true);
347✔
292
                }
347✔
293

294
                new_features.append(true);
339✔
295
            }
66✔
296
        }
297

298
        Ok(new_features.finish_cloned())
83✔
299
    }
83✔
300

301
    fn from_vec(multi_points: Vec<Self>) -> Result<Self::ArrowArray, ArrowError>
338✔
302
    where
338✔
303
        Self: Sized,
338✔
304
    {
338✔
305
        let mut builder = Self::arrow_builder(multi_points.len());
338✔
306
        for multi_point in multi_points {
2,287✔
307
            let coordinate_builder = builder.values();
1,949✔
308
            for coordinate in multi_point.as_ref() {
1,966✔
309
                let float_builder = coordinate_builder.values();
1,966✔
310
                float_builder.append_value(coordinate.x);
1,966✔
311
                float_builder.append_value(coordinate.y);
1,966✔
312
                coordinate_builder.append(true);
1,966✔
313
            }
1,966✔
314
            builder.append(true);
1,949✔
315
        }
316

317
        Ok(builder.finish_cloned())
338✔
318
    }
338✔
319
}
320

321
#[derive(Debug, PartialEq)]
322
pub struct MultiPointRef<'g> {
323
    point_coordinates: &'g [Coordinate2D],
324
}
325

326
impl<'g> MultiPointRef<'g> {
327
    pub fn new(coordinates: &'g [Coordinate2D]) -> Result<Self> {
1✔
328
        ensure!(!coordinates.is_empty(), error::UnallowedEmpty);
1✔
329

330
        Ok(Self::new_unchecked(coordinates))
1✔
331
    }
1✔
332

333
    pub(crate) fn new_unchecked(coordinates: &'g [Coordinate2D]) -> Self {
1,638✔
334
        Self {
1,638✔
335
            point_coordinates: coordinates,
1,638✔
336
        }
1,638✔
337
    }
1,638✔
338

339
    pub fn bbox(&self) -> Option<BoundingBox2D> {
×
340
        BoundingBox2D::from_coord_ref_iter(self.point_coordinates)
×
341
    }
×
342
}
343

344
impl GeometryRef for MultiPointRef<'_> {
345
    type GeometryType = MultiPoint;
346

347
    fn as_geometry(&self) -> Self::GeometryType {
×
348
        MultiPoint::from(self)
×
349
    }
×
350

351
    fn bbox(&self) -> Option<BoundingBox2D> {
×
352
        self.bbox()
×
353
    }
×
354
}
355

356
impl MultiPointAccess for MultiPointRef<'_> {
357
    fn points(&self) -> &[Coordinate2D] {
1,564✔
358
        self.point_coordinates
1,564✔
359
    }
1,564✔
360
}
361

362
impl ToWkt<f64> for MultiPointRef<'_> {
363
    fn to_wkt(&self) -> Wkt<f64> {
10✔
364
        let points = self.points();
10✔
365
        let mut multi_point = wkt::types::MultiPoint(Vec::with_capacity(points.len()));
10✔
366

367
        for point in points {
22✔
368
            multi_point.0.push(wkt::types::Point(Some(point.into())));
12✔
369
        }
12✔
370

371
        Wkt::MultiPoint(multi_point)
10✔
372
    }
10✔
373
}
374

375
impl<'g> From<MultiPointRef<'g>> for geojson::Geometry {
376
    fn from(geometry: MultiPointRef<'g>) -> geojson::Geometry {
26✔
377
        geojson::Geometry::new(match geometry.point_coordinates.len() {
26✔
378
            1 => {
379
                let floats: [f64; 2] = geometry.point_coordinates[0].into();
23✔
380
                geojson::Value::Point(floats.to_vec())
23✔
381
            }
382
            _ => geojson::Value::MultiPoint(
3✔
383
                geometry
3✔
384
                    .point_coordinates
3✔
385
                    .iter()
3✔
386
                    .map(|&c| {
6✔
387
                        let floats: [f64; 2] = c.into();
6✔
388
                        floats.to_vec()
6✔
389
                    })
6✔
390
                    .collect(),
3✔
391
            ),
3✔
392
        })
393
    }
26✔
394
}
395

396
impl<'g> From<MultiPointRef<'g>> for MultiPoint {
397
    fn from(multi_point_ref: MultiPointRef<'g>) -> Self {
15✔
398
        MultiPoint::from(&multi_point_ref)
15✔
399
    }
15✔
400
}
401

402
impl<'g> From<&MultiPointRef<'g>> for MultiPoint {
403
    fn from(multi_point_ref: &MultiPointRef<'g>) -> Self {
15✔
404
        MultiPoint::new_unchecked(multi_point_ref.point_coordinates.to_owned())
15✔
405
    }
15✔
406
}
407

408
impl<'g> From<&'g MultiPoint> for MultiPointRef<'g> {
409
    fn from(multi_point: &'g MultiPoint) -> Self {
1✔
410
        MultiPointRef::new_unchecked(&multi_point.coordinates)
1✔
411
    }
1✔
412
}
413

414
impl<A> SpatialBounded for A
415
where
416
    A: MultiPointAccess,
417
{
418
    fn spatial_bounds(&self) -> BoundingBox2D {
108✔
419
        BoundingBox2D::from_coord_ref_iter(self.points())
108✔
420
            .expect("there must be at least one cordinate in a multipoint")
108✔
421
    }
108✔
422
}
423

424
impl ApproxEq for &MultiPoint {
425
    type Margin = F64Margin;
426

427
    fn approx_eq<M: Into<Self::Margin>>(self, other: Self, margin: M) -> bool {
7✔
428
        let m = margin.into();
7✔
429
        self.coordinates.len() == other.coordinates.len()
7✔
430
            && self
6✔
431
                .coordinates
6✔
432
                .iter()
6✔
433
                .zip(other.coordinates.iter())
6✔
434
                .all(|(&a, &b)| a.approx_eq(b, m))
9✔
435
    }
7✔
436
}
437

438
#[cfg(test)]
439
mod tests {
440
    use arrow::array::{Array, ArrayBuilder};
441
    use float_cmp::approx_eq;
442

443
    use super::*;
444

445
    #[test]
446
    fn access() {
1✔
447
        fn aggregate<T: MultiPointAccess>(multi_point: &T) -> Coordinate2D {
3✔
448
            let (x, y) = multi_point
3✔
449
                .points()
3✔
450
                .iter()
3✔
451
                .fold((0., 0.), |(x, y), c| (x + c.x, y + c.y));
6✔
452
            (x, y).into()
3✔
453
        }
3✔
454

455
        let coordinates = vec![(0.0, 0.1).into(), (1.0, 1.1).into()];
1✔
456
        let multi_point = MultiPoint::new(coordinates.clone()).unwrap();
1✔
457
        let multi_point_ref = MultiPointRef::new(&coordinates).unwrap();
1✔
458

1✔
459
        let Coordinate2D { x, y } = aggregate(&multi_point);
1✔
460
        float_cmp::approx_eq!(f64, x, 1.0);
1✔
461
        float_cmp::approx_eq!(f64, y, 1.2);
1✔
462
        assert_eq!(aggregate(&multi_point), aggregate(&multi_point_ref));
1✔
463
    }
1✔
464

465
    #[test]
466
    fn intersects_bbox() -> Result<()> {
1✔
467
        let bbox = BoundingBox2D::new((0.0, 0.0).into(), (1.0, 1.0).into())?;
1✔
468

469
        assert!(MultiPoint::new(vec![(0.5, 0.5).into()])?.intersects_bbox(&bbox));
1✔
470
        assert!(MultiPoint::new(vec![(1.0, 1.0).into()])?.intersects_bbox(&bbox));
1✔
471
        assert!(MultiPoint::new(vec![(0.5, 0.5).into(), (1.5, 1.5).into()])?.intersects_bbox(&bbox));
1✔
472
        assert!(!MultiPoint::new(vec![(1.1, 1.1).into()])?.intersects_bbox(&bbox));
1✔
473
        assert!(
1✔
474
            !MultiPoint::new(vec![(-0.1, -0.1).into(), (1.1, 1.1).into()])?.intersects_bbox(&bbox)
1✔
475
        );
476

477
        Ok(())
1✔
478
    }
1✔
479

480
    #[test]
481
    fn spatial_bounds() {
1✔
482
        let expected = BoundingBox2D::new_unchecked((0., 0.).into(), (1., 1.).into());
1✔
483
        let coordinates: Vec<Coordinate2D> = Vec::from([
1✔
484
            (1., 0.4).into(),
1✔
485
            (0.8, 0.0).into(),
1✔
486
            (0.3, 0.1).into(),
1✔
487
            (0.0, 1.0).into(),
1✔
488
        ]);
1✔
489
        let mp = MultiPoint { coordinates };
1✔
490
        assert_eq!(mp.spatial_bounds(), expected);
1✔
491
    }
1✔
492

493
    #[test]
494
    fn approx_equal() {
1✔
495
        let a = MultiPoint::new(vec![
1✔
496
            (0.5, 0.5).into(),
1✔
497
            (0.5, 0.5).into(),
1✔
498
            (0.5, 0.5).into(),
1✔
499
        ])
1✔
500
        .unwrap();
1✔
501

1✔
502
        let b = MultiPoint::new(vec![
1✔
503
            (0.5, 0.499_999_999).into(),
1✔
504
            (0.5, 0.5).into(),
1✔
505
            (0.5, 0.5).into(),
1✔
506
        ])
1✔
507
        .unwrap();
1✔
508

1✔
509
        assert!(approx_eq!(&MultiPoint, &a, &b, epsilon = 0.000_001));
1✔
510
    }
1✔
511

512
    #[test]
513
    fn not_approx_equal_len() {
1✔
514
        let a = MultiPoint::new(vec![
1✔
515
            (0.5, 0.5).into(),
1✔
516
            (0.5, 0.5).into(),
1✔
517
            (0.5, 0.5).into(),
1✔
518
        ])
1✔
519
        .unwrap();
1✔
520

1✔
521
        let b = MultiPoint::new(vec![
1✔
522
            (0.5, 0.5).into(),
1✔
523
            (0.5, 0.5).into(),
1✔
524
            (0.5, 0.5).into(),
1✔
525
            (123_456_789.5, 123_456_789.5).into(),
1✔
526
        ])
1✔
527
        .unwrap();
1✔
528

1✔
529
        assert!(!approx_eq!(&MultiPoint, &a, &b, F64Margin::default()));
1✔
530
    }
1✔
531

532
    #[test]
533
    fn test_to_wkt() {
1✔
534
        let a = MultiPoint::new(vec![
1✔
535
            (0.5, 0.6).into(),
1✔
536
            (0.7, 0.8).into(),
1✔
537
            (0.9, 0.99).into(),
1✔
538
        ])
1✔
539
        .unwrap();
1✔
540

1✔
541
        let a_ref = MultiPointRef::from(&a);
1✔
542

1✔
543
        assert_eq!(
1✔
544
            a_ref.wkt_string(),
1✔
545
            "MULTIPOINT((0.5 0.6),(0.7 0.8),(0.9 0.99))"
1✔
546
        );
1✔
547
    }
1✔
548

549
    #[test]
550
    fn arrow_builder_size_points() {
1✔
551
        for num_multipoints in 0..514 {
515✔
552
            for capacity in [0, num_multipoints] {
1,028✔
553
                let mut multi_points_builder = MultiPoint::arrow_builder(capacity);
1,028✔
554

1,028✔
555
                for _ in 0..num_multipoints {
263,682✔
556
                    multi_points_builder
263,682✔
557
                        .values()
263,682✔
558
                        .values()
263,682✔
559
                        .append_values(&[1., 2.], &[true, true]);
263,682✔
560

263,682✔
561
                    multi_points_builder.values().append(true);
263,682✔
562

263,682✔
563
                    multi_points_builder.append(true);
263,682✔
564
                }
263,682✔
565

566
                assert_eq!(multi_points_builder.len(), num_multipoints);
1,028✔
567

568
                let builder_byte_size =
1,028✔
569
                    MultiPoint::estimate_array_memory_size(&mut multi_points_builder);
1,028✔
570

1,028✔
571
                let array = multi_points_builder.finish_cloned();
1,028✔
572

1,028✔
573
                assert_eq!(
1,028✔
574
                    builder_byte_size,
1,028✔
575
                    array.get_array_memory_size(),
1,028✔
576
                    "{num_multipoints}"
×
577
                );
578
            }
579
        }
580
    }
1✔
581

582
    #[test]
583
    fn arrow_builder_size_multi_points() {
1✔
584
        // TODO: test fewer multipoints?
585
        for num_multipoints in 0..514 {
515✔
586
            for capacity in [0, num_multipoints] {
1,028✔
587
                let mut multi_points_builder = MultiPoint::arrow_builder(capacity);
1,028✔
588

589
                // we have 1 point for the first multipoint, 2 for the second, etc.
590
                for num_points in 0..num_multipoints {
263,682✔
591
                    for _ in 0..num_points {
45,001,728✔
592
                        multi_points_builder
45,001,728✔
593
                            .values()
45,001,728✔
594
                            .values()
45,001,728✔
595
                            .append_values(&[1., 2.], &[true, true]);
45,001,728✔
596

45,001,728✔
597
                        multi_points_builder.values().append(true);
45,001,728✔
598
                    }
45,001,728✔
599

600
                    multi_points_builder.append(true);
263,682✔
601
                }
602

603
                assert_eq!(multi_points_builder.len(), num_multipoints);
1,028✔
604

605
                let builder_byte_size =
1,028✔
606
                    MultiPoint::estimate_array_memory_size(&mut multi_points_builder);
1,028✔
607

1,028✔
608
                let array = multi_points_builder.finish_cloned();
1,028✔
609

1,028✔
610
                assert_eq!(
1,028✔
611
                    builder_byte_size,
1,028✔
612
                    array.get_array_memory_size(),
1,028✔
613
                    "{num_multipoints}"
×
614
                );
615
            }
616
        }
617
    }
1✔
618
}
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