geoarrow_array/builder/
wkb.rs1use arrow_array::OffsetSizeTrait;
2use arrow_array::builder::GenericBinaryBuilder;
3use geo_traits::GeometryTrait;
4use geoarrow_schema::WkbType;
5use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
6use wkb::Endianness;
7use wkb::reader::Wkb;
8use wkb::writer::{WriteOptions, write_geometry};
9
10use crate::array::GenericWkbArray;
11use crate::capacity::WkbCapacity;
12
13#[derive(Debug)]
17pub struct WkbBuilder<O: OffsetSizeTrait>(GenericBinaryBuilder<O>, WkbType);
18
19impl<O: OffsetSizeTrait> WkbBuilder<O> {
20 pub fn new(typ: WkbType) -> Self {
22 Self::with_capacity(typ, Default::default())
23 }
24
25 pub fn with_capacity(typ: WkbType, capacity: WkbCapacity) -> Self {
27 Self(
28 GenericBinaryBuilder::with_capacity(
29 capacity.offsets_capacity,
30 capacity.buffer_capacity,
31 ),
32 typ,
33 )
34 }
35
36 #[inline]
43 pub fn push_geometry(
44 &mut self,
45 geom: Option<&impl GeometryTrait<T = f64>>,
46 ) -> GeoArrowResult<()> {
47 if let Some(geom) = geom {
48 let wkb_options = WriteOptions {
49 endianness: Endianness::LittleEndian,
50 };
51 write_geometry(&mut self.0, geom, &wkb_options)
52 .map_err(|err| GeoArrowError::Wkb(err.to_string()))?;
53 self.0.append_value("")
54 } else {
55 self.0.append_null()
56 };
57 Ok(())
58 }
59
60 pub fn extend_from_iter<'a>(
62 &mut self,
63 geoms: impl Iterator<Item = Option<&'a (impl GeometryTrait<T = f64> + 'a)>>,
64 ) -> GeoArrowResult<()> {
65 geoms
66 .into_iter()
67 .try_for_each(|maybe_geom| self.push_geometry(maybe_geom))?;
68 Ok(())
69 }
70
71 pub fn from_nullable_geometries(
73 geoms: &[Option<impl GeometryTrait<T = f64>>],
74 typ: WkbType,
75 ) -> GeoArrowResult<Self> {
76 let capacity = WkbCapacity::from_geometries(geoms.iter().map(|x| x.as_ref()));
77 let mut array = Self::with_capacity(typ, capacity);
78 array.extend_from_iter(geoms.iter().map(|x| x.as_ref()))?;
79 Ok(array)
80 }
81
82 #[inline]
115 pub fn push_wkb(&mut self, wkb: Option<&[u8]>) -> GeoArrowResult<()> {
116 if let Some(bytes) = wkb {
117 Wkb::try_new(bytes).map_err(|err| GeoArrowError::Wkb(err.to_string()))?;
119 self.0.append_value(bytes);
120 } else {
121 self.0.append_null();
122 }
123 Ok(())
124 }
125
126 #[inline]
169 pub unsafe fn push_wkb_unchecked(&mut self, wkb: Option<&[u8]>) {
170 if let Some(bytes) = wkb {
171 self.0.append_value(bytes);
172 } else {
173 self.0.append_null();
174 }
175 }
176
177 pub fn finish(mut self) -> GenericWkbArray<O> {
181 GenericWkbArray::new(self.0.finish(), self.1.metadata().clone())
182 }
183}
184
185#[cfg(test)]
186mod tests {
187 use super::*;
188 use crate::trait_::GeoArrowArray;
189
190 fn point_wkb() -> Vec<u8> {
192 let point = geo::Point::new(1.0, 2.0);
193 let mut buf = Vec::new();
194 wkb::writer::write_point(&mut buf, &point, &Default::default()).unwrap();
195 buf
196 }
197
198 fn point_wkb_2() -> Vec<u8> {
200 let point = geo::Point::new(3.0, 4.0);
201 let mut buf = Vec::new();
202 wkb::writer::write_point(&mut buf, &point, &Default::default()).unwrap();
203 buf
204 }
205
206 fn invalid_wkb() -> Vec<u8> {
208 vec![0x01, 0x01]
209 }
210
211 #[test]
212 fn test_push_raw_valid() {
213 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
214 let wkb = point_wkb();
215
216 builder.push_wkb(Some(&wkb)).unwrap();
218
219 let array = builder.finish();
220 assert_eq!(array.len(), 1);
221 assert!(!array.is_null(0));
222 }
223
224 #[test]
225 fn test_push_raw_multiple() {
226 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
227 let wkb1 = point_wkb();
228 let wkb2 = point_wkb_2();
229
230 builder.push_wkb(Some(&wkb1)).unwrap();
231 builder.push_wkb(Some(&wkb2)).unwrap();
232
233 let array = builder.finish();
234 assert_eq!(array.len(), 2);
235 assert!(!array.is_null(0));
236 assert!(!array.is_null(1));
237 }
238
239 #[test]
240 fn test_push_raw_null() {
241 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
242
243 builder.push_wkb(None).unwrap();
245
246 let array = builder.finish();
247 assert_eq!(array.len(), 1);
248 assert!(array.is_null(0));
249 }
250
251 #[test]
252 fn test_push_raw_mixed_with_nulls() {
253 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
254 let wkb = point_wkb();
255
256 builder.push_wkb(Some(&wkb)).unwrap();
257 builder.push_wkb(None).unwrap();
258 builder.push_wkb(Some(&wkb)).unwrap();
259
260 let array = builder.finish();
261 assert_eq!(array.len(), 3);
262 assert!(!array.is_null(0));
263 assert!(array.is_null(1));
264 assert!(!array.is_null(2));
265 }
266
267 #[test]
268 fn test_push_raw_invalid() {
269 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
270 let invalid = invalid_wkb();
271
272 let result = builder.push_wkb(Some(&invalid));
274 assert!(result.is_err());
275 }
276
277 #[test]
278 fn test_push_raw_unchecked_valid() {
279 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
280 let wkb = point_wkb();
281
282 unsafe {
283 builder.push_wkb_unchecked(Some(&wkb));
284 }
285
286 let array = builder.finish();
287 assert_eq!(array.len(), 1);
288 assert!(!array.is_null(0));
289 }
290
291 #[test]
292 fn test_push_raw_unchecked_null() {
293 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
294
295 unsafe {
296 builder.push_wkb_unchecked(None);
297 }
298
299 let array = builder.finish();
300 assert_eq!(array.len(), 1);
301 assert!(array.is_null(0));
302 }
303
304 #[test]
305 fn test_push_raw_unchecked_multiple() {
306 let mut builder = WkbBuilder::<i32>::new(WkbType::default());
307 let wkb1 = point_wkb();
308 let wkb2 = point_wkb_2();
309
310 unsafe {
311 builder.push_wkb_unchecked(Some(&wkb1));
312 builder.push_wkb_unchecked(None);
313 builder.push_wkb_unchecked(Some(&wkb2));
314 }
315
316 let array = builder.finish();
317 assert_eq!(array.len(), 3);
318 assert!(!array.is_null(0));
319 assert!(array.is_null(1));
320 assert!(!array.is_null(2));
321 }
322
323 #[test]
324 fn test_push_raw_with_i64_offset() {
325 let mut builder = WkbBuilder::<i64>::new(WkbType::default());
326 let wkb = point_wkb();
327
328 builder.push_wkb(Some(&wkb)).unwrap();
329 builder.push_wkb(None).unwrap();
330
331 let array = builder.finish();
332 assert_eq!(array.len(), 2);
333 assert!(!array.is_null(0));
334 assert!(array.is_null(1));
335 }
336}