geoarrow_array/builder/
multilinestring.rs1use std::sync::Arc;
2
3use arrow_array::OffsetSizeTrait;
4use arrow_buffer::NullBufferBuilder;
5use geo_traits::{CoordTrait, GeometryTrait, GeometryType, LineStringTrait, MultiLineStringTrait};
6use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
7use geoarrow_schema::type_id::GeometryTypeId;
8use geoarrow_schema::{Dimension, MultiLineStringType};
9
10use crate::GeoArrowArray;
11use crate::array::{GenericWkbArray, MultiLineStringArray};
12use crate::builder::{CoordBufferBuilder, OffsetsBuilder};
13use crate::capacity::MultiLineStringCapacity;
14use crate::trait_::{GeoArrowArrayAccessor, GeoArrowArrayBuilder};
15use crate::util::GeometryTypeName;
16
17#[derive(Debug)]
22pub struct MultiLineStringBuilder {
23 data_type: MultiLineStringType,
24
25 pub(crate) coords: CoordBufferBuilder,
26
27 pub(crate) geom_offsets: OffsetsBuilder<i32>,
29
30 pub(crate) ring_offsets: OffsetsBuilder<i32>,
32
33 pub(crate) validity: NullBufferBuilder,
35}
36
37impl MultiLineStringBuilder {
38 pub fn new(typ: MultiLineStringType) -> Self {
40 Self::with_capacity(typ, Default::default())
41 }
42
43 pub fn with_capacity(typ: MultiLineStringType, capacity: MultiLineStringCapacity) -> Self {
45 let coords = CoordBufferBuilder::with_capacity(
46 capacity.coord_capacity,
47 typ.coord_type(),
48 typ.dimension(),
49 );
50 Self {
51 coords,
52 geom_offsets: OffsetsBuilder::with_capacity(capacity.geom_capacity),
53 ring_offsets: OffsetsBuilder::with_capacity(capacity.ring_capacity),
54 validity: NullBufferBuilder::new(capacity.geom_capacity),
55 data_type: typ,
56 }
57 }
58
59 pub fn reserve(&mut self, additional: MultiLineStringCapacity) {
65 self.coords.reserve(additional.coord_capacity);
66 self.ring_offsets.reserve(additional.ring_capacity);
67 self.geom_offsets.reserve(additional.geom_capacity);
68 }
69
70 pub fn reserve_exact(&mut self, additional: MultiLineStringCapacity) {
82 self.coords.reserve_exact(additional.coord_capacity);
83 self.ring_offsets.reserve_exact(additional.ring_capacity);
84 self.geom_offsets.reserve_exact(additional.geom_capacity);
85 }
86
87 pub fn shrink_to_fit(&mut self) {
89 self.coords.shrink_to_fit();
90 self.ring_offsets.shrink_to_fit();
91 self.geom_offsets.shrink_to_fit();
92 }
94
95 pub fn try_new(
108 coords: CoordBufferBuilder,
109 geom_offsets: OffsetsBuilder<i32>,
110 ring_offsets: OffsetsBuilder<i32>,
111 validity: NullBufferBuilder,
112 data_type: MultiLineStringType,
113 ) -> GeoArrowResult<Self> {
114 Ok(Self {
121 coords,
122 geom_offsets,
123 ring_offsets,
124 validity,
125 data_type,
126 })
127 }
128
129 #[inline]
136 #[allow(dead_code)]
137 pub(crate) fn try_push_geom_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
138 self.geom_offsets.try_push_usize(offsets_length)?;
139 self.validity.append(true);
140 Ok(())
141 }
142
143 #[inline]
150 #[allow(dead_code)]
151 pub(crate) fn try_push_ring_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
152 self.ring_offsets.try_push_usize(offsets_length)?;
153 Ok(())
154 }
155
156 pub fn finish(mut self) -> MultiLineStringArray {
158 let validity = self.validity.finish();
159
160 MultiLineStringArray::new(
161 self.coords.finish(),
162 self.geom_offsets.finish(),
163 self.ring_offsets.finish(),
164 validity,
165 self.data_type.metadata().clone(),
166 )
167 }
168
169 #[inline]
175 pub fn push_line_string(
176 &mut self,
177 value: Option<&impl LineStringTrait<T = f64>>,
178 ) -> GeoArrowResult<()> {
179 if let Some(line_string) = value {
180 let num_line_strings = 1;
182 self.geom_offsets.try_push_usize(num_line_strings)?;
183
184 self.ring_offsets.try_push_usize(line_string.num_coords())?;
190
191 for coord in line_string.coords() {
192 self.coords.push_coord(&coord);
193 }
194
195 self.validity.append(true);
196 } else {
197 self.push_null();
198 }
199 Ok(())
200 }
201
202 #[inline]
208 pub fn push_multi_line_string(
209 &mut self,
210 value: Option<&impl MultiLineStringTrait<T = f64>>,
211 ) -> GeoArrowResult<()> {
212 if let Some(multi_line_string) = value {
213 let num_line_strings = multi_line_string.num_line_strings();
215 self.geom_offsets.try_push_usize(num_line_strings)?;
216
217 for line_string in multi_line_string.line_strings() {
224 self.ring_offsets.try_push_usize(line_string.num_coords())?;
225
226 for coord in line_string.coords() {
227 self.coords.push_coord(&coord);
228 }
229 }
230
231 self.validity.append(true);
232 } else {
233 self.push_null();
234 }
235 Ok(())
236 }
237
238 #[inline]
242 pub fn push_geometry(
243 &mut self,
244 value: Option<&impl GeometryTrait<T = f64>>,
245 ) -> GeoArrowResult<()> {
246 if let Some(value) = value {
247 match value.as_type() {
248 GeometryType::LineString(g) => self.push_line_string(Some(g))?,
249 GeometryType::MultiLineString(g) => self.push_multi_line_string(Some(g))?,
250 gt => {
251 return Err(GeoArrowError::IncorrectGeometryType(format!(
252 "Expected MultiLineString compatible geometry, got {}",
253 gt.name()
254 )));
255 }
256 }
257 } else {
258 self.push_null();
259 };
260 Ok(())
261 }
262
263 pub fn extend_from_iter<'a>(
265 &mut self,
266 geoms: impl Iterator<Item = Option<&'a (impl MultiLineStringTrait<T = f64> + 'a)>>,
267 ) {
268 geoms
269 .into_iter()
270 .try_for_each(|maybe_multi_point| self.push_multi_line_string(maybe_multi_point))
271 .unwrap();
272 }
273
274 pub fn extend_from_geometry_iter<'a>(
276 &mut self,
277 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
278 ) -> GeoArrowResult<()> {
279 geoms.into_iter().try_for_each(|g| self.push_geometry(g))?;
280 Ok(())
281 }
282
283 #[inline]
290 pub(crate) fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
291 self.coords.push_coord(coord);
292 Ok(())
293 }
294
295 #[inline]
296 pub(crate) fn push_null(&mut self) {
297 self.geom_offsets.extend_constant(1);
300 self.validity.append(false);
301 }
302
303 pub fn from_multi_line_strings(
305 geoms: &[impl MultiLineStringTrait<T = f64>],
306 typ: MultiLineStringType,
307 ) -> Self {
308 let capacity = MultiLineStringCapacity::from_multi_line_strings(geoms.iter().map(Some));
309 let mut array = Self::with_capacity(typ, capacity);
310 array.extend_from_iter(geoms.iter().map(Some));
311 array
312 }
313
314 pub fn from_nullable_multi_line_strings(
316 geoms: &[Option<impl MultiLineStringTrait<T = f64>>],
317 typ: MultiLineStringType,
318 ) -> Self {
319 let capacity =
320 MultiLineStringCapacity::from_multi_line_strings(geoms.iter().map(|x| x.as_ref()));
321 let mut array = Self::with_capacity(typ, capacity);
322 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
323 array
324 }
325
326 pub fn from_nullable_geometries(
328 geoms: &[Option<impl GeometryTrait<T = f64>>],
329 typ: MultiLineStringType,
330 ) -> GeoArrowResult<Self> {
331 let capacity = MultiLineStringCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
332 let mut array = Self::with_capacity(typ, capacity);
333 array.extend_from_geometry_iter(geoms.iter().map(|x| x.as_ref()))?;
334 Ok(array)
335 }
336}
337
338impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, MultiLineStringType)>
339 for MultiLineStringBuilder
340{
341 type Error = GeoArrowError;
342
343 fn try_from((value, typ): (GenericWkbArray<O>, MultiLineStringType)) -> GeoArrowResult<Self> {
344 let wkb_objects = value
345 .iter()
346 .map(|x| x.transpose())
347 .collect::<GeoArrowResult<Vec<_>>>()?;
348 Self::from_nullable_geometries(&wkb_objects, typ)
349 }
350}
351
352impl GeoArrowArrayBuilder for MultiLineStringBuilder {
353 fn len(&self) -> usize {
354 self.geom_offsets.len_proxy()
355 }
356
357 fn push_null(&mut self) {
358 self.push_null();
359 }
360
361 fn push_geometry(
362 &mut self,
363 geometry: Option<&impl GeometryTrait<T = f64>>,
364 ) -> GeoArrowResult<()> {
365 self.push_geometry(geometry)
366 }
367
368 fn finish(self) -> Arc<dyn GeoArrowArray> {
369 Arc::new(self.finish())
370 }
371}
372
373impl GeometryTypeId for MultiLineStringBuilder {
374 const GEOMETRY_TYPE_OFFSET: i8 = 5;
375
376 fn dimension(&self) -> Dimension {
377 self.data_type.dimension()
378 }
379}