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    /// Shrinks the capacity of self to fit.
77    pub fn shrink_to_fit(&mut self) {
78        match self {
79            CoordBufferBuilder::Interleaved(cb) => cb.shrink_to_fit(),
80            CoordBufferBuilder::Separated(cb) => cb.shrink_to_fit(),
81        }
82    }
83
84    /// Returns the total number of coordinates the vector can hold without reallocating.
85    pub fn capacity(&self) -> usize {
86        match self {
87            CoordBufferBuilder::Interleaved(cb) => cb.capacity(),
88            CoordBufferBuilder::Separated(cb) => cb.capacity(),
89        }
90    }
91
92    /// The number of coordinates
93    pub fn len(&self) -> usize {
94        match self {
95            CoordBufferBuilder::Interleaved(cb) => cb.len(),
96            CoordBufferBuilder::Separated(cb) => cb.len(),
97        }
98    }
99
100    /// Whether the buffer is empty
101    pub fn is_empty(&self) -> bool {
102        self.len() == 0
103    }
104
105    /// The underlying coordinate type
106    pub fn coord_type(&self) -> CoordType {
107        match self {
108            CoordBufferBuilder::Interleaved(_) => CoordType::Interleaved,
109            CoordBufferBuilder::Separated(_) => CoordType::Separated,
110        }
111    }
112
113    /// Push a new coord onto the end of this coordinate buffer
114    ///
115    /// ## Panics
116    ///
117    /// - If the added coordinate does not have the same dimension as the coordinate buffer.
118    pub fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) {
119        match self {
120            CoordBufferBuilder::Interleaved(cb) => cb.push_coord(coord),
121            CoordBufferBuilder::Separated(cb) => cb.push_coord(coord),
122        }
123    }
124
125    /// Push a new coord onto the end of this coordinate buffer
126    ///
127    /// ## Errors
128    ///
129    /// - If the added coordinate does not have the same dimension as the coordinate buffer.
130    pub fn try_push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
131        match self {
132            CoordBufferBuilder::Interleaved(cb) => cb.try_push_coord(coord),
133            CoordBufferBuilder::Separated(cb) => cb.try_push_coord(coord),
134        }
135    }
136
137    /// Push a valid coordinate with the given constant value
138    ///
139    /// Used in the case of point and rect arrays, where a `null` array value still needs to have
140    /// space allocated for it.
141    pub(crate) fn push_constant(&mut self, value: f64) {
142        match self {
143            CoordBufferBuilder::Interleaved(cb) => cb.push_constant(value),
144            CoordBufferBuilder::Separated(cb) => cb.push_constant(value),
145        }
146    }
147
148    /// Push a new point onto the end of this coordinate buffer
149    ///
150    /// ## Panics
151    ///
152    /// - If the added point does not have the same dimension as the coordinate buffer.
153    pub fn push_point(&mut self, point: &impl PointTrait<T = f64>) {
154        match self {
155            CoordBufferBuilder::Interleaved(cb) => cb.push_point(point),
156            CoordBufferBuilder::Separated(cb) => cb.push_point(point),
157        }
158    }
159
160    /// Push a new point onto the end of this coordinate buffer
161    ///
162    /// ## Errors
163    ///
164    /// - If the added point does not have the same dimension as the coordinate buffer.
165    pub fn try_push_point(&mut self, point: &impl PointTrait<T = f64>) -> GeoArrowResult<()> {
166        match self {
167            CoordBufferBuilder::Interleaved(cb) => cb.try_push_point(point),
168            CoordBufferBuilder::Separated(cb) => cb.try_push_point(point),
169        }
170    }
171
172    /// Consume the builder and convert to an immutable [`CoordBuffer`]
173    pub fn finish(self) -> CoordBuffer {
174        match self {
175            CoordBufferBuilder::Interleaved(cb) => CoordBuffer::Interleaved(cb.finish()),
176            CoordBufferBuilder::Separated(cb) => CoordBuffer::Separated(cb.finish()),
177        }
178    }
179}