1use std::sync::Arc;
5
6use arrow_array::OffsetSizeTrait;
7use arrow_array::builder::{
8 BinaryViewBuilder, GenericByteBuilder, GenericStringBuilder, StringViewBuilder,
9};
10use arrow_array::cast::AsArray;
11use geoarrow_schema::error::{GeoArrowError, GeoArrowResult};
12use geoarrow_schema::{GeoArrowType, WkbType};
13use wkb::Endianness;
14use wkb::writer::WriteOptions;
15
16use crate::array::*;
17use crate::builder::{
18 GeometryBuilder, GeometryCollectionBuilder, LineStringBuilder, MultiLineStringBuilder,
19 MultiPointBuilder, MultiPolygonBuilder, PointBuilder, PolygonBuilder, WkbBuilder,
20};
21use crate::trait_::GeoArrowArray;
22use crate::{GeoArrowArrayAccessor, IntoArrow};
23
24pub trait AsGeoArrowArray {
53 fn as_point_opt(&self) -> Option<&PointArray>;
55
56 #[inline]
58 fn as_point(&self) -> &PointArray {
59 self.as_point_opt().unwrap()
60 }
61
62 fn as_line_string_opt(&self) -> Option<&LineStringArray>;
64
65 #[inline]
67 fn as_line_string(&self) -> &LineStringArray {
68 self.as_line_string_opt().unwrap()
69 }
70
71 fn as_polygon_opt(&self) -> Option<&PolygonArray>;
73
74 #[inline]
76 fn as_polygon(&self) -> &PolygonArray {
77 self.as_polygon_opt().unwrap()
78 }
79
80 fn as_multi_point_opt(&self) -> Option<&MultiPointArray>;
82
83 #[inline]
85 fn as_multi_point(&self) -> &MultiPointArray {
86 self.as_multi_point_opt().unwrap()
87 }
88
89 fn as_multi_line_string_opt(&self) -> Option<&MultiLineStringArray>;
92
93 #[inline]
95 fn as_multi_line_string(&self) -> &MultiLineStringArray {
96 self.as_multi_line_string_opt().unwrap()
97 }
98
99 fn as_multi_polygon_opt(&self) -> Option<&MultiPolygonArray>;
102
103 #[inline]
105 fn as_multi_polygon(&self) -> &MultiPolygonArray {
106 self.as_multi_polygon_opt().unwrap()
107 }
108
109 fn as_geometry_collection_opt(&self) -> Option<&GeometryCollectionArray>;
112
113 #[inline]
115 fn as_geometry_collection(&self) -> &GeometryCollectionArray {
116 self.as_geometry_collection_opt().unwrap()
117 }
118
119 fn as_rect_opt(&self) -> Option<&RectArray>;
121
122 #[inline]
124 fn as_rect(&self) -> &RectArray {
125 self.as_rect_opt().unwrap()
126 }
127
128 fn as_geometry_opt(&self) -> Option<&GeometryArray>;
130
131 #[inline]
133 fn as_geometry(&self) -> &GeometryArray {
134 self.as_geometry_opt().unwrap()
135 }
136
137 fn as_wkb_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericWkbArray<O>>;
139
140 #[inline]
142 fn as_wkb<O: OffsetSizeTrait>(&self) -> &GenericWkbArray<O> {
143 self.as_wkb_opt::<O>().unwrap()
144 }
145
146 fn as_wkb_view_opt(&self) -> Option<&WkbViewArray>;
148
149 #[inline]
151 fn as_wkb_view(&self) -> &WkbViewArray {
152 self.as_wkb_view_opt().unwrap()
153 }
154
155 fn as_wkt_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericWktArray<O>>;
157
158 #[inline]
160 fn as_wkt<O: OffsetSizeTrait>(&self) -> &GenericWktArray<O> {
161 self.as_wkt_opt::<O>().unwrap()
162 }
163
164 fn as_wkt_view_opt(&self) -> Option<&WktViewArray>;
166
167 #[inline]
169 fn as_wkt_view(&self) -> &WktViewArray {
170 self.as_wkt_view_opt().unwrap()
171 }
172}
173
174impl AsGeoArrowArray for dyn GeoArrowArray + '_ {
176 #[inline]
177 fn as_point_opt(&self) -> Option<&PointArray> {
178 self.as_any().downcast_ref::<PointArray>()
179 }
180
181 #[inline]
182 fn as_line_string_opt(&self) -> Option<&LineStringArray> {
183 self.as_any().downcast_ref::<LineStringArray>()
184 }
185
186 #[inline]
187 fn as_polygon_opt(&self) -> Option<&PolygonArray> {
188 self.as_any().downcast_ref::<PolygonArray>()
189 }
190
191 #[inline]
192 fn as_multi_point_opt(&self) -> Option<&MultiPointArray> {
193 self.as_any().downcast_ref::<MultiPointArray>()
194 }
195
196 #[inline]
197 fn as_multi_line_string_opt(&self) -> Option<&MultiLineStringArray> {
198 self.as_any().downcast_ref::<MultiLineStringArray>()
199 }
200
201 #[inline]
202 fn as_multi_polygon_opt(&self) -> Option<&MultiPolygonArray> {
203 self.as_any().downcast_ref::<MultiPolygonArray>()
204 }
205
206 #[inline]
207 fn as_geometry_collection_opt(&self) -> Option<&GeometryCollectionArray> {
208 self.as_any().downcast_ref::<GeometryCollectionArray>()
209 }
210
211 #[inline]
212 fn as_rect_opt(&self) -> Option<&RectArray> {
213 self.as_any().downcast_ref::<RectArray>()
214 }
215
216 #[inline]
217 fn as_geometry_opt(&self) -> Option<&GeometryArray> {
218 self.as_any().downcast_ref::<GeometryArray>()
219 }
220
221 #[inline]
222 fn as_wkb_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericWkbArray<O>> {
223 self.as_any().downcast_ref::<GenericWkbArray<O>>()
224 }
225
226 #[inline]
227 fn as_wkb_view_opt(&self) -> Option<&WkbViewArray> {
228 self.as_any().downcast_ref::<WkbViewArray>()
229 }
230
231 #[inline]
232 fn as_wkt_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericWktArray<O>> {
233 self.as_any().downcast_ref::<GenericWktArray<O>>()
234 }
235
236 #[inline]
237 fn as_wkt_view_opt(&self) -> Option<&WktViewArray> {
238 self.as_any().downcast_ref::<WktViewArray>()
239 }
240}
241
242impl AsGeoArrowArray for Arc<dyn GeoArrowArray> {
243 #[inline]
244 fn as_point_opt(&self) -> Option<&PointArray> {
245 self.as_any().downcast_ref::<PointArray>()
246 }
247
248 #[inline]
249 fn as_line_string_opt(&self) -> Option<&LineStringArray> {
250 self.as_any().downcast_ref::<LineStringArray>()
251 }
252
253 #[inline]
254 fn as_polygon_opt(&self) -> Option<&PolygonArray> {
255 self.as_any().downcast_ref::<PolygonArray>()
256 }
257
258 #[inline]
259 fn as_multi_point_opt(&self) -> Option<&MultiPointArray> {
260 self.as_any().downcast_ref::<MultiPointArray>()
261 }
262
263 #[inline]
264 fn as_multi_line_string_opt(&self) -> Option<&MultiLineStringArray> {
265 self.as_any().downcast_ref::<MultiLineStringArray>()
266 }
267
268 #[inline]
269 fn as_multi_polygon_opt(&self) -> Option<&MultiPolygonArray> {
270 self.as_any().downcast_ref::<MultiPolygonArray>()
271 }
272
273 #[inline]
274 fn as_geometry_collection_opt(&self) -> Option<&GeometryCollectionArray> {
275 self.as_any().downcast_ref::<GeometryCollectionArray>()
276 }
277
278 #[inline]
279 fn as_rect_opt(&self) -> Option<&RectArray> {
280 self.as_any().downcast_ref::<RectArray>()
281 }
282
283 #[inline]
284 fn as_geometry_opt(&self) -> Option<&GeometryArray> {
285 self.as_any().downcast_ref::<GeometryArray>()
286 }
287
288 #[inline]
289 fn as_wkb_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericWkbArray<O>> {
290 self.as_any().downcast_ref::<GenericWkbArray<O>>()
291 }
292
293 #[inline]
294 fn as_wkb_view_opt(&self) -> Option<&WkbViewArray> {
295 self.as_any().downcast_ref::<WkbViewArray>()
296 }
297
298 #[inline]
299 fn as_wkt_opt<O: OffsetSizeTrait>(&self) -> Option<&GenericWktArray<O>> {
300 self.as_any().downcast_ref::<GenericWktArray<O>>()
301 }
302
303 #[inline]
304 fn as_wkt_view_opt(&self) -> Option<&WktViewArray> {
305 self.as_any().downcast_ref::<WktViewArray>()
306 }
307}
308
309pub fn to_wkb<O: OffsetSizeTrait>(arr: &dyn GeoArrowArray) -> GeoArrowResult<GenericWkbArray<O>> {
311 use GeoArrowType::*;
312 match arr.data_type() {
313 Point(_) => impl_to_wkb(arr.as_point()),
314 LineString(_) => impl_to_wkb(arr.as_line_string()),
315 Polygon(_) => impl_to_wkb(arr.as_polygon()),
316 MultiPoint(_) => impl_to_wkb(arr.as_multi_point()),
317 MultiLineString(_) => impl_to_wkb(arr.as_multi_line_string()),
318 MultiPolygon(_) => impl_to_wkb(arr.as_multi_polygon()),
319 Geometry(_) => impl_to_wkb(arr.as_geometry()),
320 GeometryCollection(_) => impl_to_wkb(arr.as_geometry_collection()),
321 Rect(_) => impl_to_wkb(arr.as_rect()),
322 Wkb(typ) => {
323 if O::IS_LARGE {
325 let large_arr: GenericWkbArray<i64> = arr.as_wkb::<i32>().clone().into();
327 let array = large_arr.to_array_ref().as_binary::<O>().clone();
328 Ok(GenericWkbArray::new(array, typ.metadata().clone()))
329 } else {
330 let array = arr.as_wkb::<i32>().to_array_ref();
333 let array = array.as_binary::<O>().clone();
334 Ok(GenericWkbArray::new(array, typ.metadata().clone()))
335 }
336 }
337 LargeWkb(typ) => {
338 if O::IS_LARGE {
339 let array = arr.as_wkb::<i64>().to_array_ref();
342 let array = array.as_binary::<O>().clone();
343 Ok(GenericWkbArray::new(array, typ.metadata().clone()))
344 } else {
345 let small_arr: GenericWkbArray<i32> = arr.as_wkb::<i64>().clone().try_into()?;
347 let array = small_arr.to_array_ref().as_binary::<O>().clone();
348 Ok(GenericWkbArray::new(array, typ.metadata().clone()))
349 }
350 }
351 WkbView(_) => {
352 let wkb_view_arr = arr.as_wkb_view();
353 let metadata = wkb_view_arr.data_type().metadata().clone();
354 let array = wkb_view_arr.clone().into_arrow();
355
356 let mut builder = GenericByteBuilder::new();
357 array.iter().for_each(|value| builder.append_option(value));
358 Ok(GenericWkbArray::new(builder.finish(), metadata))
359 }
360 Wkt(_) => impl_to_wkb(arr.as_wkt::<i32>()),
361 LargeWkt(_) => impl_to_wkb(arr.as_wkt::<i64>()),
362 WktView(_) => impl_to_wkb(arr.as_wkt_view()),
363 }
364}
365
366fn impl_to_wkb<'a, O: OffsetSizeTrait>(
367 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
368) -> GeoArrowResult<GenericWkbArray<O>> {
369 let geoms = geo_arr
370 .iter()
371 .map(|x| x.transpose())
372 .collect::<GeoArrowResult<Vec<_>>>()?;
373 let wkb_type = WkbType::new(geo_arr.data_type().metadata().clone());
374 Ok(WkbBuilder::from_nullable_geometries(geoms.as_slice(), wkb_type).finish())
375}
376
377pub fn to_wkb_view(arr: &dyn GeoArrowArray) -> GeoArrowResult<WkbViewArray> {
379 use GeoArrowType::*;
380 match arr.data_type() {
381 Point(_) => impl_to_wkb_view(arr.as_point()),
382 LineString(_) => impl_to_wkb_view(arr.as_line_string()),
383 Polygon(_) => impl_to_wkb_view(arr.as_polygon()),
384 MultiPoint(_) => impl_to_wkb_view(arr.as_multi_point()),
385 MultiLineString(_) => impl_to_wkb_view(arr.as_multi_line_string()),
386 MultiPolygon(_) => impl_to_wkb_view(arr.as_multi_polygon()),
387 Geometry(_) => impl_to_wkb_view(arr.as_geometry()),
388 GeometryCollection(_) => impl_to_wkb_view(arr.as_geometry_collection()),
389 Rect(_) => impl_to_wkb_view(arr.as_rect()),
390 Wkb(_) => impl_to_wkb_view(arr.as_wkb::<i32>()),
391 LargeWkb(_) => impl_to_wkb_view(arr.as_wkb::<i64>()),
392 WkbView(_) => Ok(arr.as_wkb_view().clone()),
393 Wkt(_) => impl_to_wkb_view(arr.as_wkt::<i32>()),
394 LargeWkt(_) => impl_to_wkb_view(arr.as_wkt::<i64>()),
395 WktView(_) => impl_to_wkb_view(arr.as_wkt_view()),
396 }
397}
398
399fn impl_to_wkb_view<'a>(
400 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
401) -> GeoArrowResult<WkbViewArray> {
402 let geoms = geo_arr
403 .iter()
404 .map(|x| x.transpose())
405 .collect::<GeoArrowResult<Vec<_>>>()?;
406
407 let mut builder = BinaryViewBuilder::new();
408 let wkb_options = WriteOptions {
409 endianness: Endianness::LittleEndian,
410 };
411 for maybe_geom in geoms {
412 if let Some(geom) = maybe_geom {
413 let mut buf = Vec::new();
414 wkb::writer::write_geometry(&mut buf, &geom, &wkb_options).unwrap();
415 builder.append_value(buf);
416 } else {
417 builder.append_null();
418 }
419 }
420
421 let binary_view_arr = builder.finish();
422 Ok(WkbViewArray::new(
423 binary_view_arr,
424 geo_arr.data_type().metadata().clone(),
425 ))
426}
427
428pub fn from_wkb<'a, A: GenericWkbArrayType<'a>>(
437 arr: &'a A,
438 to_type: GeoArrowType,
439) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
440 let geoms = arr
441 .iter()
442 .map(|g| g.transpose())
443 .collect::<GeoArrowResult<Vec<_>>>()?;
444
445 use GeoArrowType::*;
446 let result: Arc<dyn GeoArrowArray> = match to_type {
447 Point(typ) => Arc::new(PointBuilder::from_nullable_geometries(&geoms, typ)?.finish()),
448 LineString(typ) => {
449 Arc::new(LineStringBuilder::from_nullable_geometries(&geoms, typ)?.finish())
450 }
451 Polygon(typ) => Arc::new(PolygonBuilder::from_nullable_geometries(&geoms, typ)?.finish()),
452 MultiPoint(typ) => {
453 Arc::new(MultiPointBuilder::from_nullable_geometries(&geoms, typ)?.finish())
454 }
455 MultiLineString(typ) => {
456 Arc::new(MultiLineStringBuilder::from_nullable_geometries(&geoms, typ)?.finish())
457 }
458 MultiPolygon(typ) => {
459 Arc::new(MultiPolygonBuilder::from_nullable_geometries(&geoms, typ)?.finish())
460 }
461 GeometryCollection(typ) => {
462 Arc::new(GeometryCollectionBuilder::from_nullable_geometries(&geoms, typ)?.finish())
463 }
464 Rect(_) => {
465 return Err(GeoArrowError::IncorrectGeometryType(format!(
466 "Cannot decode WKB geometries to Rect geometry type in from_wkb {:?}",
467 to_type,
468 )));
469 }
470 Geometry(typ) => Arc::new(GeometryBuilder::from_nullable_geometries(&geoms, typ)?.finish()),
471 Wkb(typ) => {
472 let mut wkb_arr = to_wkb::<i32>(arr)?;
473 wkb_arr.data_type = typ;
474 Arc::new(wkb_arr)
475 }
476 LargeWkb(typ) => {
477 let mut wkb_arr = to_wkb::<i64>(arr)?;
478 wkb_arr.data_type = typ;
479 Arc::new(wkb_arr)
480 }
481 WkbView(typ) => {
482 let mut wkb_view_arr = to_wkb_view(arr)?;
483 wkb_view_arr.data_type = typ;
484 Arc::new(wkb_view_arr)
485 }
486 Wkt(typ) => {
487 let mut wkt_arr = to_wkt::<i32>(arr)?;
488 wkt_arr.data_type = typ;
489 Arc::new(wkt_arr)
490 }
491 LargeWkt(typ) => {
492 let mut wkt_arr = to_wkt::<i64>(arr)?;
493 wkt_arr.data_type = typ;
494 Arc::new(wkt_arr)
495 }
496 WktView(typ) => {
497 let mut wkt_view_arr = to_wkt_view(arr)?;
498 wkt_view_arr.data_type = typ;
499 Arc::new(wkt_view_arr)
500 }
501 };
502 Ok(result)
503}
504
505pub fn to_wkt<O: OffsetSizeTrait>(arr: &dyn GeoArrowArray) -> GeoArrowResult<GenericWktArray<O>> {
507 use GeoArrowType::*;
508 match arr.data_type() {
509 Point(_) => impl_to_wkt(arr.as_point()),
510 LineString(_) => impl_to_wkt(arr.as_line_string()),
511 Polygon(_) => impl_to_wkt(arr.as_polygon()),
512 MultiPoint(_) => impl_to_wkt(arr.as_multi_point()),
513 MultiLineString(_) => impl_to_wkt(arr.as_multi_line_string()),
514 MultiPolygon(_) => impl_to_wkt(arr.as_multi_polygon()),
515 Geometry(_) => impl_to_wkt(arr.as_geometry()),
516 GeometryCollection(_) => impl_to_wkt(arr.as_geometry_collection()),
517 Rect(_) => impl_to_wkt(arr.as_rect()),
518 Wkb(_) => impl_to_wkt(arr.as_wkb::<i32>()),
519 LargeWkb(_) => impl_to_wkt(arr.as_wkb::<i64>()),
520 WkbView(_) => impl_to_wkt(arr.as_wkb_view()),
521 Wkt(typ) => {
522 if O::IS_LARGE {
523 let large_arr: GenericWktArray<i64> = arr.as_wkt::<i32>().clone().into();
524 let array = large_arr.to_array_ref().as_string::<O>().clone();
525 Ok(GenericWktArray::new(array, typ.metadata().clone()))
526 } else {
527 let array = arr.as_wkt::<i32>().to_array_ref();
530 let array = array.as_string::<O>().clone();
531 Ok(GenericWktArray::new(array, typ.metadata().clone()))
532 }
533 }
534 LargeWkt(typ) => {
535 if O::IS_LARGE {
536 let array = arr.as_wkt::<i64>().to_array_ref();
539 let array = array.as_string::<O>().clone();
540 Ok(GenericWktArray::new(array, typ.metadata().clone()))
541 } else {
542 let small_arr: GenericWktArray<i32> = arr.as_wkt::<i64>().clone().try_into()?;
543 let array = small_arr.to_array_ref().as_string::<O>().clone();
544 Ok(GenericWktArray::new(array, typ.metadata().clone()))
545 }
546 }
547 WktView(_) => {
548 todo!("fast path that casts a string array to a wkt view array")
549 }
550 }
551}
552
553fn impl_to_wkt<'a, O: OffsetSizeTrait>(
554 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
555) -> GeoArrowResult<GenericWktArray<O>> {
556 let metadata = geo_arr.data_type().metadata().clone();
557 let mut builder = GenericStringBuilder::new();
558
559 for maybe_geom in geo_arr.iter() {
560 if let Some(geom) = maybe_geom {
561 wkt::to_wkt::write_geometry(&mut builder, &geom?)
562 .map_err(|err| GeoArrowError::External(Box::new(err)))?;
563 builder.append_value("");
564 } else {
565 builder.append_null();
566 }
567 }
568
569 Ok(GenericWktArray::new(builder.finish(), metadata))
570}
571
572pub fn to_wkt_view(arr: &dyn GeoArrowArray) -> GeoArrowResult<WktViewArray> {
574 use GeoArrowType::*;
575 match arr.data_type() {
576 Point(_) => impl_to_wkt_view(arr.as_point()),
577 LineString(_) => impl_to_wkt_view(arr.as_line_string()),
578 Polygon(_) => impl_to_wkt_view(arr.as_polygon()),
579 MultiPoint(_) => impl_to_wkt_view(arr.as_multi_point()),
580 MultiLineString(_) => impl_to_wkt_view(arr.as_multi_line_string()),
581 MultiPolygon(_) => impl_to_wkt_view(arr.as_multi_polygon()),
582 Geometry(_) => impl_to_wkt_view(arr.as_geometry()),
583 GeometryCollection(_) => impl_to_wkt_view(arr.as_geometry_collection()),
584 Rect(_) => impl_to_wkt_view(arr.as_rect()),
585 Wkb(_) => impl_to_wkt_view(arr.as_wkb::<i32>()),
586 LargeWkb(_) => impl_to_wkt_view(arr.as_wkb::<i64>()),
587 WkbView(_) => impl_to_wkt_view(arr.as_wkb_view()),
588 Wkt(_) => impl_to_wkt_view(arr.as_wkt::<i32>()),
589 LargeWkt(_) => impl_to_wkt_view(arr.as_wkt::<i64>()),
590 WktView(_) => Ok(arr.as_wkt_view().clone()),
591 }
592}
593
594fn impl_to_wkt_view<'a>(
595 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
596) -> GeoArrowResult<WktViewArray> {
597 let metadata = geo_arr.data_type().metadata().clone();
598 let mut builder = StringViewBuilder::new();
599
600 for maybe_geom in geo_arr.iter() {
601 if let Some(geom) = maybe_geom {
602 let mut s = String::new();
603 wkt::to_wkt::write_geometry(&mut s, &geom?)
604 .map_err(|err| GeoArrowError::External(Box::new(err)))?;
605 builder.append_value(s);
606 } else {
607 builder.append_null();
608 }
609 }
610
611 Ok(WktViewArray::new(builder.finish(), metadata))
612}
613
614pub fn from_wkt<A: GenericWktArrayType>(
620 arr: &A,
621 to_type: GeoArrowType,
622) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
623 let geoms = arr
624 .iter()
625 .map(|g| g.transpose())
626 .collect::<GeoArrowResult<Vec<_>>>()?;
627
628 use GeoArrowType::*;
629 let result: Arc<dyn GeoArrowArray> = match to_type {
630 Point(typ) => Arc::new(PointBuilder::from_nullable_geometries(&geoms, typ)?.finish()),
631 LineString(typ) => {
632 Arc::new(LineStringBuilder::from_nullable_geometries(&geoms, typ)?.finish())
633 }
634 Polygon(typ) => Arc::new(PolygonBuilder::from_nullable_geometries(&geoms, typ)?.finish()),
635 MultiPoint(typ) => {
636 Arc::new(MultiPointBuilder::from_nullable_geometries(&geoms, typ)?.finish())
637 }
638 MultiLineString(typ) => {
639 Arc::new(MultiLineStringBuilder::from_nullable_geometries(&geoms, typ)?.finish())
640 }
641 MultiPolygon(typ) => {
642 Arc::new(MultiPolygonBuilder::from_nullable_geometries(&geoms, typ)?.finish())
643 }
644 GeometryCollection(typ) => {
645 Arc::new(GeometryCollectionBuilder::from_nullable_geometries(&geoms, typ)?.finish())
646 }
647 Rect(_) => {
648 return Err(GeoArrowError::IncorrectGeometryType(format!(
649 "Cannot decode WKT geometries to Rect geometry type in from_wkt {:?}",
650 to_type,
651 )));
652 }
653 Geometry(typ) => Arc::new(GeometryBuilder::from_nullable_geometries(&geoms, typ)?.finish()),
654 Wkb(typ) => {
655 let mut wkb_arr = to_wkb::<i32>(arr)?;
656 wkb_arr.data_type = typ;
657 Arc::new(wkb_arr)
658 }
659 LargeWkb(typ) => {
660 let mut wkb_arr = to_wkb::<i64>(arr)?;
661 wkb_arr.data_type = typ;
662 Arc::new(wkb_arr)
663 }
664 WkbView(typ) => {
665 let mut wkb_view_arr = to_wkb_view(arr)?;
666 wkb_view_arr.data_type = typ;
667 Arc::new(wkb_view_arr)
668 }
669 Wkt(typ) => {
670 let mut wkt_arr = to_wkt::<i32>(arr)?;
671 wkt_arr.data_type = typ;
672 Arc::new(wkt_arr)
673 }
674 LargeWkt(typ) => {
675 let mut wkt_arr = to_wkt::<i64>(arr)?;
676 wkt_arr.data_type = typ;
677 Arc::new(wkt_arr)
678 }
679 WktView(typ) => {
680 let mut wkt_view_arr = to_wkt_view(arr)?;
681 wkt_view_arr.data_type = typ;
682 Arc::new(wkt_view_arr)
683 }
684 };
685 Ok(result)
686}
687
688#[doc(hidden)]
692pub mod __private {
693 pub use geoarrow_schema::GeoArrowType;
694}
695
696#[macro_export]
773macro_rules! downcast_geoarrow_array {
774 ($array:ident, $fn:expr) => {
775 match $array.data_type() {
776 $crate::cast::__private::GeoArrowType::Point(_) => {
777 $fn($crate::cast::AsGeoArrowArray::as_point($array))
778 }
779 $crate::cast::__private::GeoArrowType::LineString(_) => {
780 $fn($crate::cast::AsGeoArrowArray::as_line_string($array))
781 }
782 $crate::cast::__private::GeoArrowType::Polygon(_) => {
783 $fn($crate::cast::AsGeoArrowArray::as_polygon($array))
784 }
785 $crate::cast::__private::GeoArrowType::MultiPoint(_) => {
786 $fn($crate::cast::AsGeoArrowArray::as_multi_point($array))
787 }
788 $crate::cast::__private::GeoArrowType::MultiLineString(_) => {
789 $fn($crate::cast::AsGeoArrowArray::as_multi_line_string($array))
790 }
791 $crate::cast::__private::GeoArrowType::MultiPolygon(_) => {
792 $fn($crate::cast::AsGeoArrowArray::as_multi_polygon($array))
793 }
794 $crate::cast::__private::GeoArrowType::Geometry(_) => {
795 $fn($crate::cast::AsGeoArrowArray::as_geometry($array))
796 }
797 $crate::cast::__private::GeoArrowType::GeometryCollection(_) => $fn(
798 $crate::cast::AsGeoArrowArray::as_geometry_collection($array),
799 ),
800 $crate::cast::__private::GeoArrowType::Rect(_) => {
801 $fn($crate::cast::AsGeoArrowArray::as_rect($array))
802 }
803 $crate::cast::__private::GeoArrowType::Wkb(_) => {
804 $fn($crate::cast::AsGeoArrowArray::as_wkb::<i32>($array))
805 }
806 $crate::cast::__private::GeoArrowType::LargeWkb(_) => {
807 $fn($crate::cast::AsGeoArrowArray::as_wkb::<i64>($array))
808 }
809 $crate::cast::__private::GeoArrowType::WkbView(_) => {
810 $fn($crate::cast::AsGeoArrowArray::as_wkb_view($array))
811 }
812 $crate::cast::__private::GeoArrowType::Wkt(_) => {
813 $fn($crate::cast::AsGeoArrowArray::as_wkt::<i32>($array))
814 }
815 $crate::cast::__private::GeoArrowType::LargeWkt(_) => {
816 $fn($crate::cast::AsGeoArrowArray::as_wkt::<i64>($array))
817 }
818 $crate::cast::__private::GeoArrowType::WktView(_) => {
819 $fn($crate::cast::AsGeoArrowArray::as_wkt_view($array))
820 }
821 }
822 };
823}
824
825#[cfg(test)]
826mod test {
827 use geoarrow_schema::{CoordType, Dimension, WkbType};
828
829 use super::*;
830 use crate::test;
831
832 #[test]
833 fn test_cast_wkb_in_to_wkb() {
834 let wkb_arr: GenericWkbArray<i32> =
835 to_wkb(&test::point::array(CoordType::Separated, Dimension::XY)).unwrap();
836 let wkb_arr2: GenericWkbArray<i32> = to_wkb(&wkb_arr).unwrap();
837 let wkb_arr3: GenericWkbArray<i64> = to_wkb(&wkb_arr2).unwrap();
838 let wkb_arr4: GenericWkbArray<i64> = to_wkb(&wkb_arr3).unwrap();
839 let wkb_arr5: GenericWkbArray<i32> = to_wkb(&wkb_arr4).unwrap();
840 assert_eq!(wkb_arr, wkb_arr5);
841 }
842
843 #[test]
844 fn test_cast_wkt_in_to_wkt() {
845 let wkt_arr: GenericWktArray<i32> =
846 to_wkt(&test::point::array(CoordType::Separated, Dimension::XY)).unwrap();
847 let wkt_arr2: GenericWktArray<i32> = to_wkt(&wkt_arr).unwrap();
848 let wkt_arr3: GenericWktArray<i64> = to_wkt(&wkt_arr2).unwrap();
849 let wkt_arr4: GenericWktArray<i64> = to_wkt(&wkt_arr3).unwrap();
850 let wkt_arr5: GenericWktArray<i32> = to_wkt(&wkt_arr4).unwrap();
851 assert_eq!(wkt_arr, wkt_arr5);
852 }
853
854 #[test]
856 fn test_round_trip_wkb_point() {
857 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
858 for dim in [
859 Dimension::XY,
860 Dimension::XYZ,
861 Dimension::XYM,
862 Dimension::XYZM,
863 ] {
864 let arr = test::point::array(coord_type, dim);
865
866 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
867 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
868 assert_eq!(&arr, arr2.as_point());
869
870 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
871 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
872 assert_eq!(&arr, arr3.as_point());
873 }
874 }
875 }
876
877 #[test]
878 fn test_round_trip_wkb_linestring() {
879 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
880 for dim in [
881 Dimension::XY,
882 Dimension::XYZ,
883 Dimension::XYM,
884 Dimension::XYZM,
885 ] {
886 let arr = test::linestring::array(coord_type, dim);
887
888 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
889 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
890 assert_eq!(&arr, arr2.as_line_string());
891
892 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
893 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
894 assert_eq!(&arr, arr3.as_line_string());
895 }
896 }
897 }
898
899 #[test]
900 fn test_round_trip_wkb_polygon() {
901 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
902 for dim in [
903 Dimension::XY,
904 Dimension::XYZ,
905 Dimension::XYM,
906 Dimension::XYZM,
907 ] {
908 let arr = test::polygon::array(coord_type, dim);
909
910 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
911 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
912 assert_eq!(&arr, arr2.as_polygon());
913
914 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
915 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
916 assert_eq!(&arr, arr3.as_polygon());
917 }
918 }
919 }
920
921 #[test]
922 fn test_round_trip_wkb_multipoint() {
923 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
924 for dim in [
925 Dimension::XY,
926 Dimension::XYZ,
927 Dimension::XYM,
928 Dimension::XYZM,
929 ] {
930 let arr = test::multipoint::array(coord_type, dim);
931
932 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
933 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
934 assert_eq!(&arr, arr2.as_multi_point());
935
936 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
937 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
938 assert_eq!(&arr, arr3.as_multi_point());
939 }
940 }
941 }
942
943 #[test]
944 fn test_round_trip_wkb_multilinestring() {
945 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
946 for dim in [
947 Dimension::XY,
948 Dimension::XYZ,
949 Dimension::XYM,
950 Dimension::XYZM,
951 ] {
952 let arr = test::multilinestring::array(coord_type, dim);
953
954 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
955 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
956 assert_eq!(&arr, arr2.as_multi_line_string());
957
958 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
959 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
960 assert_eq!(&arr, arr3.as_multi_line_string());
961 }
962 }
963 }
964
965 #[test]
966 fn test_round_trip_wkb_multipolygon() {
967 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
968 for dim in [
969 Dimension::XY,
970 Dimension::XYZ,
971 Dimension::XYM,
972 Dimension::XYZM,
973 ] {
974 let arr = test::multipolygon::array(coord_type, dim);
975
976 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
977 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
978 assert_eq!(&arr, arr2.as_multi_polygon());
979
980 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
981 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
982 assert_eq!(&arr, arr3.as_multi_polygon());
983 }
984 }
985 }
986
987 #[test]
988 fn test_round_trip_wkb_geometrycollection() {
989 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
990 for dim in [
991 Dimension::XY,
992 Dimension::XYZ,
993 Dimension::XYM,
994 Dimension::XYZM,
995 ] {
996 let arr = test::geometrycollection::array(coord_type, dim, false);
997
998 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
999 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
1000 assert_eq!(&arr, arr2.as_geometry_collection());
1001
1002 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
1003 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1004 assert_eq!(&arr, arr3.as_geometry_collection());
1005 }
1006 }
1007 }
1008
1009 #[test]
1010 fn test_round_trip_wkb_geometry() {
1011 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1012 let arr = test::geometry::array(coord_type, false);
1013
1014 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
1015 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
1016 assert_eq!(&arr, arr2.as_geometry());
1017
1018 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
1019 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1020 assert_eq!(&arr, arr3.as_geometry());
1021 }
1022 }
1023
1024 #[test]
1026 fn test_round_trip_wkt_point() {
1027 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1028 for dim in [
1029 Dimension::XY,
1030 Dimension::XYZ,
1031 Dimension::XYM,
1032 Dimension::XYZM,
1033 ] {
1034 let arr = test::point::array(coord_type, dim);
1035
1036 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1037 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1038 assert_eq!(&arr, arr2.as_point());
1039
1040 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1041 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1042 assert_eq!(&arr, arr3.as_point());
1043 }
1044 }
1045 }
1046
1047 #[test]
1048 fn test_round_trip_wkt_linestring() {
1049 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1050 for dim in [
1051 Dimension::XY,
1052 Dimension::XYZ,
1053 Dimension::XYM,
1054 Dimension::XYZM,
1055 ] {
1056 let arr = test::linestring::array(coord_type, dim);
1057
1058 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1059 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1060 assert_eq!(&arr, arr2.as_line_string());
1061
1062 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1063 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1064 assert_eq!(&arr, arr3.as_line_string());
1065 }
1066 }
1067 }
1068
1069 #[test]
1070 fn test_round_trip_wkt_polygon() {
1071 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1072 for dim in [
1073 Dimension::XY,
1074 Dimension::XYZ,
1075 Dimension::XYM,
1076 Dimension::XYZM,
1077 ] {
1078 let arr = test::polygon::array(coord_type, dim);
1079
1080 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1081 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1082 assert_eq!(&arr, arr2.as_polygon());
1083
1084 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1085 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1086 assert_eq!(&arr, arr3.as_polygon());
1087 }
1088 }
1089 }
1090
1091 #[test]
1092 fn test_round_trip_wkt_multipoint() {
1093 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1094 for dim in [
1095 Dimension::XY,
1096 Dimension::XYZ,
1097 Dimension::XYM,
1098 Dimension::XYZM,
1099 ] {
1100 let arr = test::multipoint::array(coord_type, dim);
1101
1102 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1103 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1104 assert_eq!(&arr, arr2.as_multi_point());
1105
1106 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1107 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1108 assert_eq!(&arr, arr3.as_multi_point());
1109 }
1110 }
1111 }
1112
1113 #[test]
1114 fn test_round_trip_wkt_multilinestring() {
1115 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1116 for dim in [
1117 Dimension::XY,
1118 Dimension::XYZ,
1119 Dimension::XYM,
1120 Dimension::XYZM,
1121 ] {
1122 let arr = test::multilinestring::array(coord_type, dim);
1123
1124 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1125 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1126 assert_eq!(&arr, arr2.as_multi_line_string());
1127
1128 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1129 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1130 assert_eq!(&arr, arr3.as_multi_line_string());
1131 }
1132 }
1133 }
1134
1135 #[test]
1136 fn test_round_trip_wkt_multipolygon() {
1137 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1138 for dim in [
1139 Dimension::XY,
1140 Dimension::XYZ,
1141 Dimension::XYM,
1142 Dimension::XYZM,
1143 ] {
1144 let arr = test::multipolygon::array(coord_type, dim);
1145
1146 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1147 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1148 assert_eq!(&arr, arr2.as_multi_polygon());
1149
1150 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1151 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1152 assert_eq!(&arr, arr3.as_multi_polygon());
1153 }
1154 }
1155 }
1156
1157 #[test]
1158 fn test_round_trip_wkt_geometrycollection() {
1159 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1160 for dim in [
1161 Dimension::XY,
1162 Dimension::XYZ,
1163 Dimension::XYM,
1164 Dimension::XYZM,
1165 ] {
1166 let arr = test::geometrycollection::array(coord_type, dim, false);
1167
1168 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1169 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1170 assert_eq!(&arr, arr2.as_geometry_collection());
1171
1172 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1173 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1174 assert_eq!(&arr, arr3.as_geometry_collection());
1175 }
1176 }
1177 }
1178
1179 #[test]
1180 fn test_round_trip_wkt_geometry() {
1181 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1182 let arr = test::geometry::array(coord_type, false);
1183
1184 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1185 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1186 assert_eq!(&arr, arr2.as_geometry());
1187
1188 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1189 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1190 assert_eq!(&arr, arr3.as_geometry());
1191 }
1192 }
1193
1194 #[allow(dead_code)]
1196 fn _to_wkb_test_downcast_macro(
1197 arr: &dyn GeoArrowArray,
1198 ) -> GeoArrowResult<GenericWkbArray<i32>> {
1199 downcast_geoarrow_array!(arr, impl_to_wkb)
1200 }
1201
1202 fn impl_to_wkb<'a>(
1203 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
1204 ) -> GeoArrowResult<GenericWkbArray<i32>> {
1205 let geoms = geo_arr
1206 .iter()
1207 .map(|x| x.transpose())
1208 .collect::<std::result::Result<Vec<_>, _>>()
1209 .unwrap();
1210 let wkb_type = WkbType::new(geo_arr.data_type().metadata().clone());
1211 Ok(WkbBuilder::from_nullable_geometries(geoms.as_slice(), wkb_type).finish())
1212 }
1213}