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 try_new(
99 coords: CoordBufferBuilder,
100 geom_offsets: OffsetsBuilder<i32>,
101 ring_offsets: OffsetsBuilder<i32>,
102 validity: NullBufferBuilder,
103 data_type: MultiLineStringType,
104 ) -> GeoArrowResult<Self> {
105 Ok(Self {
112 coords,
113 geom_offsets,
114 ring_offsets,
115 validity,
116 data_type,
117 })
118 }
119
120 #[inline]
127 pub(crate) fn try_push_geom_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
128 self.geom_offsets.try_push_usize(offsets_length)?;
129 self.validity.append(true);
130 Ok(())
131 }
132
133 #[inline]
140 pub(crate) fn try_push_ring_offset(&mut self, offsets_length: usize) -> GeoArrowResult<()> {
141 self.ring_offsets.try_push_usize(offsets_length)?;
142 Ok(())
143 }
144
145 pub fn finish(mut self) -> MultiLineStringArray {
147 let validity = self.validity.finish();
148
149 MultiLineStringArray::new(
150 self.coords.finish(),
151 self.geom_offsets.finish(),
152 self.ring_offsets.finish(),
153 validity,
154 self.data_type.metadata().clone(),
155 )
156 }
157
158 #[inline]
164 pub fn push_line_string(
165 &mut self,
166 value: Option<&impl LineStringTrait<T = f64>>,
167 ) -> GeoArrowResult<()> {
168 if let Some(line_string) = value {
169 let num_line_strings = 1;
171 self.geom_offsets.try_push_usize(num_line_strings)?;
172
173 self.ring_offsets
179 .try_push_usize(line_string.num_coords())
180 .unwrap();
181
182 for coord in line_string.coords() {
183 self.coords.push_coord(&coord);
184 }
185
186 self.validity.append(true);
187 } else {
188 self.push_null();
189 }
190 Ok(())
191 }
192
193 #[inline]
199 pub fn push_multi_line_string(
200 &mut self,
201 value: Option<&impl MultiLineStringTrait<T = f64>>,
202 ) -> GeoArrowResult<()> {
203 if let Some(multi_line_string) = value {
204 let num_line_strings = multi_line_string.num_line_strings();
206 self.geom_offsets.try_push_usize(num_line_strings)?;
207
208 for line_string in multi_line_string.line_strings() {
215 self.ring_offsets
216 .try_push_usize(line_string.num_coords())
217 .unwrap();
218
219 for coord in line_string.coords() {
220 self.coords.push_coord(&coord);
221 }
222 }
223
224 self.validity.append(true);
225 } else {
226 self.push_null();
227 }
228 Ok(())
229 }
230
231 #[inline]
235 pub fn push_geometry(
236 &mut self,
237 value: Option<&impl GeometryTrait<T = f64>>,
238 ) -> GeoArrowResult<()> {
239 if let Some(value) = value {
240 match value.as_type() {
241 GeometryType::LineString(g) => self.push_line_string(Some(g))?,
242 GeometryType::MultiLineString(g) => self.push_multi_line_string(Some(g))?,
243 gt => {
244 return Err(GeoArrowError::IncorrectGeometryType(format!(
245 "Expected MultiLineString compatible geometry, got {}",
246 gt.name()
247 )));
248 }
249 }
250 } else {
251 self.push_null();
252 };
253 Ok(())
254 }
255
256 pub fn extend_from_iter<'a>(
258 &mut self,
259 geoms: impl Iterator<Item = Option<&'a (impl MultiLineStringTrait<T = f64> + 'a)>>,
260 ) {
261 geoms
262 .into_iter()
263 .try_for_each(|maybe_multi_point| self.push_multi_line_string(maybe_multi_point))
264 .unwrap();
265 }
266
267 pub fn extend_from_geometry_iter<'a>(
269 &mut self,
270 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
271 ) -> GeoArrowResult<()> {
272 geoms.into_iter().try_for_each(|g| self.push_geometry(g))?;
273 Ok(())
274 }
275
276 #[inline]
283 pub(crate) fn push_coord(&mut self, coord: &impl CoordTrait<T = f64>) -> GeoArrowResult<()> {
284 self.coords.push_coord(coord);
285 Ok(())
286 }
287
288 #[inline]
289 pub(crate) fn push_null(&mut self) {
290 self.geom_offsets.extend_constant(1);
293 self.validity.append(false);
294 }
295
296 pub fn from_multi_line_strings(
298 geoms: &[impl MultiLineStringTrait<T = f64>],
299 typ: MultiLineStringType,
300 ) -> Self {
301 let capacity = MultiLineStringCapacity::from_multi_line_strings(geoms.iter().map(Some));
302 let mut array = Self::with_capacity(typ, capacity);
303 array.extend_from_iter(geoms.iter().map(Some));
304 array
305 }
306
307 pub fn from_nullable_multi_line_strings(
309 geoms: &[Option<impl MultiLineStringTrait<T = f64>>],
310 typ: MultiLineStringType,
311 ) -> Self {
312 let capacity =
313 MultiLineStringCapacity::from_multi_line_strings(geoms.iter().map(|x| x.as_ref()));
314 let mut array = Self::with_capacity(typ, capacity);
315 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()));
316 array
317 }
318
319 pub fn from_nullable_geometries(
321 geoms: &[Option<impl GeometryTrait<T = f64>>],
322 typ: MultiLineStringType,
323 ) -> GeoArrowResult<Self> {
324 let capacity = MultiLineStringCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()))?;
325 let mut array = Self::with_capacity(typ, capacity);
326 array.extend_from_geometry_iter(geoms.iter().map(|x| x.as_ref()))?;
327 Ok(array)
328 }
329}
330
331impl<O: OffsetSizeTrait> TryFrom<(GenericWkbArray<O>, MultiLineStringType)>
332 for MultiLineStringBuilder
333{
334 type Error = GeoArrowError;
335
336 fn try_from((value, typ): (GenericWkbArray<O>, MultiLineStringType)) -> GeoArrowResult<Self> {
337 let wkb_objects = value
338 .iter()
339 .map(|x| x.transpose())
340 .collect::<GeoArrowResult<Vec<_>>>()?;
341 Self::from_nullable_geometries(&wkb_objects, typ)
342 }
343}
344
345impl GeoArrowArrayBuilder for MultiLineStringBuilder {
346 fn len(&self) -> usize {
347 self.geom_offsets.len_proxy()
348 }
349
350 fn push_null(&mut self) {
351 self.push_null();
352 }
353
354 fn push_geometry(
355 &mut self,
356 geometry: Option<&impl GeometryTrait<T = f64>>,
357 ) -> GeoArrowResult<()> {
358 self.push_geometry(geometry)
359 }
360
361 fn finish(self) -> Arc<dyn GeoArrowArray> {
362 Arc::new(self.finish())
363 }
364}