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 pub(crate) fn try_push_geom_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
136 self.geom_offsets.try_push_usize(offsets_length)?;
137 self.validity.append(true);
138 Ok(())
139 }
140
141 #[inline]
148 pub(crate) fn try_push_ring_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
149 self.ring_offsets.try_push_usize(offsets_length)?;
150 Ok(())
151 }
152
153 pub fn finish(mut self) -> MultiLineStringArray {
155 let validity = self.validity.finish();
156
157 MultiLineStringArray::new(
158 self.coords.finish(),
159 self.geom_offsets.finish(),
160 self.ring_offsets.finish(),
161 validity,
162 self.data_type.metadata().clone(),
163 )
164 }
165
166 #[inline]
172 pub fn push_line_string(
173 &mut self,
174 value: Option<&impl LineStringTrait<T = f64>>,
175 ) -> GeoArrowResult<()> {
176 if let Some(line_string) = value {
177 let num_line_strings = 1;
179 self.geom_offsets.try_push_usize(num_line_strings)?;
180
181 self.ring_offsets.try_push_usize(line_string.num_coords())?;
187
188 for coord in line_string.coords() {
189 self.coords.push_coord(&coord);
190 }
191
192 self.validity.append(true);
193 } else {
194 self.push_null();
195 }
196 Ok(())
197 }
198
199 #[inline]
205 pub fn push_multi_line_string(
206 &mut self,
207 value: Option<&impl MultiLineStringTrait<T = f64>>,
208 ) -> GeoArrowResult<()> {
209 if let Some(multi_line_string) = value {
210 let num_line_strings = multi_line_string.num_line_strings();
212 self.geom_offsets.try_push_usize(num_line_strings)?;
213
214 for line_string in multi_line_string.line_strings() {
221 self.ring_offsets.try_push_usize(line_string.num_coords())?;
222
223 for coord in line_string.coords() {
224 self.coords.push_coord(&coord);
225 }
226 }
227
228 self.validity.append(true);
229 } else {
230 self.push_null();
231 }
232 Ok(())
233 }
234
235 #[inline]
239 pub fn push_geometry(
240 &mut self,
241 value: Option<&impl GeometryTrait<T = f64>>,
242 ) -> GeoArrowResult<()> {
243 if let Some(value) = value {
244 match value.as_type() {
245 GeometryType::LineString(g) => self.push_line_string(Some(g))?,
246 GeometryType::MultiLineString(g) => self.push_multi_line_string(Some(g))?,
247 gt => {
248 return Err(GeoArrowError::IncorrectGeometryType(format!(
249 "Expected MultiLineString compatible geometry, got {}",
250 gt.name()
251 )));
252 }
253 }
254 } else {
255 self.push_null();
256 };
257 Ok(())
258 }
259
260 pub fn extend_from_iter<'a>(
262 &mut self,
263 geoms: impl Iterator<Item = Option<&'a (impl MultiLineStringTrait<T = f64> + 'a)>>,
264 ) {
265 geoms
266 .into_iter()
267 .try_for_each(|maybe_multi_point| self.push_multi_line_string(maybe_multi_point))
268 .unwrap();
269 }
270
271 pub fn extend_from_geometry_iter<'a>(
273 &mut self,
274 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
275 ) -> GeoArrowResult<()> {
276 geoms.into_iter().try_for_each(|g| self.push_geometry(g))?;
277 Ok(())
278 }
279
280 #[inline]
287 pub(crate) fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
288 self.coords.push_coord(coord);
289 Ok(())
290 }
291
292 #[inline]
293 pub(crate) fn push_null(&mut self) {
294 self.geom_offsets.extend_constant(1);
297 self.validity.append(false);
298 }
299
300 pub fn from_multi_line_strings(
302 geoms: &[impl MultiLineStringTrait<T = f64>],
303 typ: MultiLineStringType,
304 ) -> Self {
305 let capacity = MultiLineStringCapacity::from_multi_line_strings(geoms.iter().map(Some));
306 let mut array = Self::with_capacity(typ, capacity);
307 array.extend_from_iter(geoms.iter().map(Some));
308 array
309 }
310
311 pub fn from_nullable_multi_line_strings(
313 geoms: &[Option<impl MultiLineStringTrait<T = f64>>],
314 typ: MultiLineStringType,
315 ) -> Self {
316 let capacity =
317 MultiLineStringCapacity::from_multi_line_strings(geoms.iter().map(|x| x.as_ref()));
318 let mut array = Self::with_capacity(typ, capacity);
319 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
320 array
321 }
322
323 pub fn from_nullable_geometries(
325 geoms: &[Option<impl GeometryTrait<T = f64>>],
326 typ: MultiLineStringType,
327 ) -> GeoArrowResult<Self> {
328 let capacity = MultiLineStringCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
329 let mut array = Self::with_capacity(typ, capacity);
330 array.extend_from_geometry_iter(geoms.iter().map(|x| x.as_ref()))?;
331 Ok(array)
332 }
333}
334
335impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, MultiLineStringType)>
336 for MultiLineStringBuilder
337{
338 type Error = GeoArrowError;
339
340 fn try_from((value, typ): (GenericWkbArray<O>, MultiLineStringType)) -> GeoArrowResult<Self> {
341 let wkb_objects = value
342 .iter()
343 .map(|x| x.transpose())
344 .collect::<GeoArrowResult<Vec<_>>>()?;
345 Self::from_nullable_geometries(&wkb_objects, typ)
346 }
347}
348
349impl GeoArrowArrayBuilder for MultiLineStringBuilder {
350 fn len(&self) -> usize {
351 self.geom_offsets.len_proxy()
352 }
353
354 fn push_null(&mut self) {
355 self.push_null();
356 }
357
358 fn push_geometry(
359 &mut self,
360 geometry: Option<&impl GeometryTrait<T = f64>>,
361 ) -> GeoArrowResult<()> {
362 self.push_geometry(geometry)
363 }
364
365 fn finish(self) -> Arc<dyn GeoArrowArray> {
366 Arc::new(self.finish())
367 }
368}