geoarrow_array/builder/coord/
combined.rs

1use core::f64;
2
3use geo_traits::{CoordTrait, PointTrait};
4use geoarrow_schema::error::GeoArrowResult;
5use geoarrow_schema::{CoordType, Dimension};
6
7use crate::array::CoordBuffer;
8use crate::builder::{InterleavedCoordBufferBuilder, SeparatedCoordBufferBuilder};
9
10/// The GeoArrow equivalent to `Vec<Coord>`: a mutable collection of coordinates.
11///
12/// Converting an [`CoordBufferBuilder`] into a [`CoordBuffer`] is `O(1)`.
13#[derive(Debug, Clone)]
14pub enum CoordBufferBuilder {
15    /// Interleaved coordinates
16    Interleaved(InterleavedCoordBufferBuilder),
17    /// Separated coordinates
18    Separated(SeparatedCoordBufferBuilder),
19}
20
21impl CoordBufferBuilder {
22    /// Initialize a buffer of a given length with all coordinates set to the given value.
23    pub fn initialize(len: usize, coord_type: CoordType, dim: Dimension, value: f64) -> Self {
24        match coord_type {
25            CoordType::Interleaved => CoordBufferBuilder::Interleaved(
26                InterleavedCoordBufferBuilder::initialize(len, dim, value),
27            ),
28            CoordType::Separated => CoordBufferBuilder::Separated(
29                SeparatedCoordBufferBuilder::initialize(len, dim, value),
30            ),
31        }
32    }
33
34    /// Create a new builder with the given capacity and dimension
35    pub fn with_capacity(len: usize, coord_type: CoordType, dim: Dimension) -> Self {
36        match coord_type {
37            CoordType::Interleaved => CoordBufferBuilder::Interleaved(
38                InterleavedCoordBufferBuilder::with_capacity(len, dim),
39            ),
40            CoordType::Separated => {
41                CoordBufferBuilder::Separated(SeparatedCoordBufferBuilder::with_capacity(len, dim))
42            }
43        }
44    }
45
46    /// Reserves capacity for at least `additional` more coordinates to be inserted
47    /// in the given `Vec<T>`. The collection may reserve more space to
48    /// speculatively avoid frequent reallocations. After calling `reserve`,
49    /// capacity will be greater than or equal to `self.len() + additional`.
50    /// Does nothing if capacity is already sufficient.
51    pub fn reserve(&mut self, additional: usize) {
52        match self {
53            CoordBufferBuilder::Interleaved(cb) => cb.reserve(additional),
54            CoordBufferBuilder::Separated(cb) => cb.reserve(additional),
55        }
56    }
57
58    /// Reserves the minimum capacity for at least `additional` more coordinates.
59    ///
60    /// Unlike [`reserve`], this will not deliberately over-allocate to speculatively avoid
61    /// frequent allocations. After calling `reserve_exact`, capacity will be greater than or equal
62    /// to `self.len() + additional`. Does nothing if the capacity is already sufficient.
63    ///
64    /// Note that the allocator may give the collection more space than it
65    /// requests. Therefore, capacity can not be relied upon to be precisely
66    /// minimal. Prefer [`reserve`] if future insertions are expected.
67    ///
68    /// [`reserve`]: Self::reserve
69    pub fn reserve_exact(&mut self, additional: usize) {
70        match self {
71            CoordBufferBuilder::Interleaved(cb) => cb.reserve_exact(additional),
72            CoordBufferBuilder::Separated(cb) => cb.reserve_exact(additional),
73        }
74    }
75
76    /// Returns the total number of coordinates the vector can hold without reallocating.
77    pub fn capacity(&self) -> usize {
78        match self {
79            CoordBufferBuilder::Interleaved(cb) => cb.capacity(),
80            CoordBufferBuilder::Separated(cb) => cb.capacity(),
81        }
82    }
83
84    /// The number of coordinates
85    pub fn len(&self) -> usize {
86        match self {
87            CoordBufferBuilder::Interleaved(cb) => cb.len(),
88            CoordBufferBuilder::Separated(cb) => cb.len(),
89        }
90    }
91
92    /// Whether the buffer is empty
93    pub fn is_empty(&self) -> bool {
94        self.len() == 0
95    }
96
97    /// The underlying coordinate type
98    pub fn coord_type(&self) -> CoordType {
99        match self {
100            CoordBufferBuilder::Interleaved(_) => CoordType::Interleaved,
101            CoordBufferBuilder::Separated(_) => CoordType::Separated,
102        }
103    }
104
105    /// Push a new coord onto the end of this coordinate buffer
106    ///
107    /// ## Panics
108    ///
109    /// - If the added coordinate does not have the same dimension as the coordinate buffer.
110    pub fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) {
111        match self {
112            CoordBufferBuilder::Interleaved(cb) => cb.push_coord(coord),
113            CoordBufferBuilder::Separated(cb) => cb.push_coord(coord),
114        }
115    }
116
117    /// Push a new coord onto the end of this coordinate buffer
118    ///
119    /// ## Errors
120    ///
121    /// - If the added coordinate does not have the same dimension as the coordinate buffer.
122    pub fn try_push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
123        match self {
124            CoordBufferBuilder::Interleaved(cb) => cb.try_push_coord(coord),
125            CoordBufferBuilder::Separated(cb) => cb.try_push_coord(coord),
126        }
127    }
128
129    /// Push a valid coordinate with the given constant value
130    ///
131    /// Used in the case of point and rect arrays, where a `null` array value still needs to have
132    /// space allocated for it.
133    pub(crate) fn push_constant(&mut self, value: f64) {
134        match self {
135            CoordBufferBuilder::Interleaved(cb) => cb.push_constant(value),
136            CoordBufferBuilder::Separated(cb) => cb.push_constant(value),
137        }
138    }
139
140    /// Push a new point onto the end of this coordinate buffer
141    ///
142    /// ## Panics
143    ///
144    /// - If the added point does not have the same dimension as the coordinate buffer.
145    pub fn push_point(&mut self, point: &impl PointTrait<T = f64>) {
146        match self {
147            CoordBufferBuilder::Interleaved(cb) => cb.push_point(point),
148            CoordBufferBuilder::Separated(cb) => cb.push_point(point),
149        }
150    }
151
152    /// Push a new point onto the end of this coordinate buffer
153    ///
154    /// ## Errors
155    ///
156    /// - If the added point does not have the same dimension as the coordinate buffer.
157    pub fn try_push_point(&mut self, point: &impl PointTrait<T = f64>) -> GeoArrowResult<()> {
158        match self {
159            CoordBufferBuilder::Interleaved(cb) => cb.try_push_point(point),
160            CoordBufferBuilder::Separated(cb) => cb.try_push_point(point),
161        }
162    }
163
164    /// Consume the builder and convert to an immutable [`CoordBuffer`]
165    pub fn finish(self) -> CoordBuffer {
166        match self {
167            CoordBufferBuilder::Interleaved(cb) => CoordBuffer::Interleaved(cb.finish()),
168            CoordBufferBuilder::Separated(cb) => CoordBuffer::Separated(cb.finish()),
169        }
170    }
171}