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