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::with_capacity(arr.len(), 0);
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(_) => wkb_array_to_wkb_view(arr.as_wkb::<i32>()),
391 LargeWkb(_) => wkb_array_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>(
403 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
404) -> GeoArrowResult<WkbViewArray> {
405 let geoms = geo_arr
406 .iter()
407 .map(|x| x.transpose())
408 .collect::<GeoArrowResult<Vec<_>>>()?;
409
410 let mut builder = BinaryViewBuilder::with_capacity(geo_arr.len());
411 let wkb_options = WriteOptions {
412 endianness: Endianness::LittleEndian,
413 };
414 for maybe_geom in geoms {
415 if let Some(geom) = maybe_geom {
416 let mut buf = Vec::new();
417 wkb::writer::write_geometry(&mut buf, &geom, &wkb_options).unwrap();
418 builder.append_value(buf);
419 } else {
420 builder.append_null();
421 }
422 }
423
424 let binary_view_arr = builder.finish();
425 Ok(WkbViewArray::new(
426 binary_view_arr,
427 geo_arr.data_type().metadata().clone(),
428 ))
429}
430
431fn wkb_array_to_wkb_view<O: OffsetSizeTrait>(
433 arr: &GenericWkbArray<O>,
434) -> GeoArrowResult<WkbViewArray> {
435 let metadata = arr.data_type().metadata().clone();
436 let mut builder = BinaryViewBuilder::with_capacity(arr.len());
437
438 for value in arr.inner().iter() {
439 if let Some(bytes) = value {
440 builder.append_value(bytes);
441 } else {
442 builder.append_null();
443 }
444 }
445
446 Ok(WkbViewArray::new(builder.finish(), metadata))
447}
448
449pub fn from_wkb<'a, A: GenericWkbArrayType<'a>>(
458 arr: &'a A,
459 to_type: GeoArrowType,
460) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
461 let geoms_fn = || {
464 arr.iter()
465 .map(|g| g.transpose())
466 .collect::<GeoArrowResult<Vec<_>>>()
467 };
468
469 use GeoArrowType::*;
470 let result: Arc<dyn GeoArrowArray> = match to_type {
471 Point(typ) => Arc::new(PointBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish()),
472 LineString(typ) => {
473 Arc::new(LineStringBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
474 }
475 Polygon(typ) => {
476 Arc::new(PolygonBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
477 }
478 MultiPoint(typ) => {
479 Arc::new(MultiPointBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
480 }
481 MultiLineString(typ) => {
482 Arc::new(MultiLineStringBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
483 }
484 MultiPolygon(typ) => {
485 Arc::new(MultiPolygonBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
486 }
487 GeometryCollection(typ) => Arc::new(
488 GeometryCollectionBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish(),
489 ),
490 Rect(_) => {
491 return Err(GeoArrowError::IncorrectGeometryType(format!(
492 "Cannot decode WKB geometries to Rect geometry type in from_wkb {to_type:?}",
493 )));
494 }
495 Geometry(typ) => {
496 Arc::new(GeometryBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
497 }
498 Wkb(typ) => {
499 let mut wkb_arr = to_wkb::<i32>(arr)?;
500 wkb_arr.data_type = typ;
501 Arc::new(wkb_arr)
502 }
503 LargeWkb(typ) => {
504 let mut wkb_arr = to_wkb::<i64>(arr)?;
505 wkb_arr.data_type = typ;
506 Arc::new(wkb_arr)
507 }
508 WkbView(typ) => {
509 let mut wkb_view_arr = to_wkb_view(arr)?;
510 wkb_view_arr.data_type = typ;
511 Arc::new(wkb_view_arr)
512 }
513 Wkt(typ) => {
514 let mut wkt_arr = to_wkt::<i32>(arr)?;
515 wkt_arr.data_type = typ;
516 Arc::new(wkt_arr)
517 }
518 LargeWkt(typ) => {
519 let mut wkt_arr = to_wkt::<i64>(arr)?;
520 wkt_arr.data_type = typ;
521 Arc::new(wkt_arr)
522 }
523 WktView(typ) => {
524 let mut wkt_view_arr = to_wkt_view(arr)?;
525 wkt_view_arr.data_type = typ;
526 Arc::new(wkt_view_arr)
527 }
528 };
529 Ok(result)
530}
531
532pub fn to_wkt<O: OffsetSizeTrait>(arr: &dyn GeoArrowArray) -> GeoArrowResult<GenericWktArray<O>> {
534 use GeoArrowType::*;
535 match arr.data_type() {
536 Point(_) => impl_to_wkt(arr.as_point()),
537 LineString(_) => impl_to_wkt(arr.as_line_string()),
538 Polygon(_) => impl_to_wkt(arr.as_polygon()),
539 MultiPoint(_) => impl_to_wkt(arr.as_multi_point()),
540 MultiLineString(_) => impl_to_wkt(arr.as_multi_line_string()),
541 MultiPolygon(_) => impl_to_wkt(arr.as_multi_polygon()),
542 Geometry(_) => impl_to_wkt(arr.as_geometry()),
543 GeometryCollection(_) => impl_to_wkt(arr.as_geometry_collection()),
544 Rect(_) => impl_to_wkt(arr.as_rect()),
545 Wkb(_) => impl_to_wkt(arr.as_wkb::<i32>()),
546 LargeWkb(_) => impl_to_wkt(arr.as_wkb::<i64>()),
547 WkbView(_) => impl_to_wkt(arr.as_wkb_view()),
548 Wkt(typ) => {
549 if O::IS_LARGE {
550 let large_arr: GenericWktArray<i64> = arr.as_wkt::<i32>().clone().into();
551 let array = large_arr.to_array_ref().as_string::<O>().clone();
552 Ok(GenericWktArray::new(array, typ.metadata().clone()))
553 } else {
554 let array = arr.as_wkt::<i32>().to_array_ref();
557 let array = array.as_string::<O>().clone();
558 Ok(GenericWktArray::new(array, typ.metadata().clone()))
559 }
560 }
561 LargeWkt(typ) => {
562 if O::IS_LARGE {
563 let array = arr.as_wkt::<i64>().to_array_ref();
566 let array = array.as_string::<O>().clone();
567 Ok(GenericWktArray::new(array, typ.metadata().clone()))
568 } else {
569 let small_arr: GenericWktArray<i32> = arr.as_wkt::<i64>().clone().try_into()?;
570 let array = small_arr.to_array_ref().as_string::<O>().clone();
571 Ok(GenericWktArray::new(array, typ.metadata().clone()))
572 }
573 }
574 WktView(_) => {
575 let wkt_view_arr = arr.as_wkt_view();
576 let metadata = wkt_view_arr.data_type().metadata().clone();
577 let array = wkt_view_arr.clone().into_arrow();
578
579 let mut builder = GenericStringBuilder::with_capacity(arr.len(), 0);
580 array.iter().for_each(|value| builder.append_option(value));
581 Ok(GenericWktArray::new(builder.finish(), metadata))
582 }
583 }
584}
585
586fn impl_to_wkt<'a, O: OffsetSizeTrait>(
587 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
588) -> GeoArrowResult<GenericWktArray<O>> {
589 let metadata = geo_arr.data_type().metadata().clone();
590 let mut builder = GenericStringBuilder::with_capacity(geo_arr.len(), 0);
591
592 for maybe_geom in geo_arr.iter() {
593 if let Some(geom) = maybe_geom {
594 wkt::to_wkt::write_geometry(&mut builder, &geom?)
595 .map_err(|err| GeoArrowError::External(Box::new(err)))?;
596 builder.append_value("");
597 } else {
598 builder.append_null();
599 }
600 }
601
602 Ok(GenericWktArray::new(builder.finish(), metadata))
603}
604
605pub fn to_wkt_view(arr: &dyn GeoArrowArray) -> GeoArrowResult<WktViewArray> {
607 use GeoArrowType::*;
608 match arr.data_type() {
609 Point(_) => impl_to_wkt_view(arr.as_point()),
610 LineString(_) => impl_to_wkt_view(arr.as_line_string()),
611 Polygon(_) => impl_to_wkt_view(arr.as_polygon()),
612 MultiPoint(_) => impl_to_wkt_view(arr.as_multi_point()),
613 MultiLineString(_) => impl_to_wkt_view(arr.as_multi_line_string()),
614 MultiPolygon(_) => impl_to_wkt_view(arr.as_multi_polygon()),
615 Geometry(_) => impl_to_wkt_view(arr.as_geometry()),
616 GeometryCollection(_) => impl_to_wkt_view(arr.as_geometry_collection()),
617 Rect(_) => impl_to_wkt_view(arr.as_rect()),
618 Wkb(_) => impl_to_wkt_view(arr.as_wkb::<i32>()),
619 LargeWkb(_) => impl_to_wkt_view(arr.as_wkb::<i64>()),
620 WkbView(_) => impl_to_wkt_view(arr.as_wkb_view()),
621 Wkt(_) => wkt_array_to_wkt_view(arr.as_wkt::<i32>()),
622 LargeWkt(_) => wkt_array_to_wkt_view(arr.as_wkt::<i64>()),
623 WktView(_) => Ok(arr.as_wkt_view().clone()),
624 }
625}
626
627fn impl_to_wkt_view<'a>(
631 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
632) -> GeoArrowResult<WktViewArray> {
633 let metadata = geo_arr.data_type().metadata().clone();
634 let mut builder = StringViewBuilder::with_capacity(geo_arr.len());
635
636 for maybe_geom in geo_arr.iter() {
637 if let Some(geom) = maybe_geom {
638 let mut s = String::new();
639 wkt::to_wkt::write_geometry(&mut s, &geom?)
640 .map_err(|err| GeoArrowError::External(Box::new(err)))?;
641 builder.append_value(s);
642 } else {
643 builder.append_null();
644 }
645 }
646
647 Ok(WktViewArray::new(builder.finish(), metadata))
648}
649
650fn wkt_array_to_wkt_view<O: OffsetSizeTrait>(
652 arr: &GenericWktArray<O>,
653) -> GeoArrowResult<WktViewArray> {
654 let metadata = arr.data_type().metadata().clone();
655 let mut builder = StringViewBuilder::with_capacity(arr.len());
656
657 for value in arr.inner().iter() {
658 if let Some(s) = value {
659 builder.append_value(s);
660 } else {
661 builder.append_null();
662 }
663 }
664
665 Ok(WktViewArray::new(builder.finish(), metadata))
666}
667
668pub fn from_wkt<A: GenericWktArrayType>(
674 arr: &A,
675 to_type: GeoArrowType,
676) -> GeoArrowResult<Arc<dyn GeoArrowArray>> {
677 let geoms_fn = || {
680 arr.iter()
681 .map(|g| g.transpose())
682 .collect::<GeoArrowResult<Vec<_>>>()
683 };
684
685 use GeoArrowType::*;
686 let result: Arc<dyn GeoArrowArray> = match to_type {
687 Point(typ) => Arc::new(PointBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish()),
688 LineString(typ) => {
689 Arc::new(LineStringBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
690 }
691 Polygon(typ) => {
692 Arc::new(PolygonBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
693 }
694 MultiPoint(typ) => {
695 Arc::new(MultiPointBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
696 }
697 MultiLineString(typ) => {
698 Arc::new(MultiLineStringBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
699 }
700 MultiPolygon(typ) => {
701 Arc::new(MultiPolygonBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
702 }
703 GeometryCollection(typ) => Arc::new(
704 GeometryCollectionBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish(),
705 ),
706 Rect(_) => {
707 return Err(GeoArrowError::IncorrectGeometryType(format!(
708 "Cannot decode WKT geometries to Rect geometry type in from_wkt {to_type:?}",
709 )));
710 }
711 Geometry(typ) => {
712 Arc::new(GeometryBuilder::from_nullable_geometries(&geoms_fn()?, typ)?.finish())
713 }
714 Wkb(typ) => {
715 let mut wkb_arr = to_wkb::<i32>(arr)?;
716 wkb_arr.data_type = typ;
717 Arc::new(wkb_arr)
718 }
719 LargeWkb(typ) => {
720 let mut wkb_arr = to_wkb::<i64>(arr)?;
721 wkb_arr.data_type = typ;
722 Arc::new(wkb_arr)
723 }
724 WkbView(typ) => {
725 let mut wkb_view_arr = to_wkb_view(arr)?;
726 wkb_view_arr.data_type = typ;
727 Arc::new(wkb_view_arr)
728 }
729 Wkt(typ) => {
730 let mut wkt_arr = to_wkt::<i32>(arr)?;
731 wkt_arr.data_type = typ;
732 Arc::new(wkt_arr)
733 }
734 LargeWkt(typ) => {
735 let mut wkt_arr = to_wkt::<i64>(arr)?;
736 wkt_arr.data_type = typ;
737 Arc::new(wkt_arr)
738 }
739 WktView(typ) => {
740 let mut wkt_view_arr = to_wkt_view(arr)?;
741 wkt_view_arr.data_type = typ;
742 Arc::new(wkt_view_arr)
743 }
744 };
745 Ok(result)
746}
747
748#[doc(hidden)]
752pub mod __private {
753 pub use geoarrow_schema::GeoArrowType;
754}
755
756#[macro_export]
833macro_rules! downcast_geoarrow_array {
834 ($array:ident, $fn:expr $(, $args:expr )* $(,)?) => {
835 match $array.data_type() {
836 $crate::cast::__private::GeoArrowType::Point(_) => {
837 $fn($crate::cast::AsGeoArrowArray::as_point($array) $(, $args )*)
838 }
839 $crate::cast::__private::GeoArrowType::LineString(_) => {
840 $fn($crate::cast::AsGeoArrowArray::as_line_string($array) $(, $args )*)
841 }
842 $crate::cast::__private::GeoArrowType::Polygon(_) => {
843 $fn($crate::cast::AsGeoArrowArray::as_polygon($array) $(, $args )*)
844 }
845 $crate::cast::__private::GeoArrowType::MultiPoint(_) => {
846 $fn($crate::cast::AsGeoArrowArray::as_multi_point($array) $(, $args )*)
847 }
848 $crate::cast::__private::GeoArrowType::MultiLineString(_) => {
849 $fn($crate::cast::AsGeoArrowArray::as_multi_line_string($array) $(, $args )*)
850 }
851 $crate::cast::__private::GeoArrowType::MultiPolygon(_) => {
852 $fn($crate::cast::AsGeoArrowArray::as_multi_polygon($array) $(, $args )*)
853 }
854 $crate::cast::__private::GeoArrowType::Geometry(_) => {
855 $fn($crate::cast::AsGeoArrowArray::as_geometry($array) $(, $args )*)
856 }
857 $crate::cast::__private::GeoArrowType::GeometryCollection(_) => $fn(
858 $crate::cast::AsGeoArrowArray::as_geometry_collection($array) $(, $args )*
859 ),
860 $crate::cast::__private::GeoArrowType::Rect(_) => {
861 $fn($crate::cast::AsGeoArrowArray::as_rect($array) $(, $args )*)
862 }
863 $crate::cast::__private::GeoArrowType::Wkb(_) => {
864 $fn($crate::cast::AsGeoArrowArray::as_wkb::<i32>($array) $(, $args )*)
865 }
866 $crate::cast::__private::GeoArrowType::LargeWkb(_) => {
867 $fn($crate::cast::AsGeoArrowArray::as_wkb::<i64>($array) $(, $args )*)
868 }
869 $crate::cast::__private::GeoArrowType::WkbView(_) => {
870 $fn($crate::cast::AsGeoArrowArray::as_wkb_view($array) $(, $args )*)
871 }
872 $crate::cast::__private::GeoArrowType::Wkt(_) => {
873 $fn($crate::cast::AsGeoArrowArray::as_wkt::<i32>($array) $(, $args )*)
874 }
875 $crate::cast::__private::GeoArrowType::LargeWkt(_) => {
876 $fn($crate::cast::AsGeoArrowArray::as_wkt::<i64>($array) $(, $args )*)
877 }
878 $crate::cast::__private::GeoArrowType::WktView(_) => {
879 $fn($crate::cast::AsGeoArrowArray::as_wkt_view($array) $(, $args )*)
880 }
881 }
882 };
883}
884
885#[cfg(test)]
886mod test {
887 use std::sync::Arc;
888
889 use geoarrow_schema::{CoordType, Dimension, WkbType};
890
891 use super::*;
892 use crate::test;
893
894 #[test]
895 fn test_cast_wkb_in_to_wkb() {
896 let wkb_arr: GenericWkbArray<i32> =
897 to_wkb(&test::point::array(CoordType::Separated, Dimension::XY)).unwrap();
898 let wkb_arr2: GenericWkbArray<i32> = to_wkb(&wkb_arr).unwrap();
899 let wkb_arr3: GenericWkbArray<i64> = to_wkb(&wkb_arr2).unwrap();
900 let wkb_arr4: GenericWkbArray<i64> = to_wkb(&wkb_arr3).unwrap();
901 let wkb_arr5: GenericWkbArray<i32> = to_wkb(&wkb_arr4).unwrap();
902 assert_eq!(wkb_arr, wkb_arr5);
903 }
904
905 #[test]
906 fn test_cast_wkt_in_to_wkt() {
907 let wkt_arr: GenericWktArray<i32> =
908 to_wkt(&test::point::array(CoordType::Separated, Dimension::XY)).unwrap();
909 let wkt_arr2: GenericWktArray<i32> = to_wkt(&wkt_arr).unwrap();
910 let wkt_arr3: GenericWktArray<i64> = to_wkt(&wkt_arr2).unwrap();
911 let wkt_arr4: GenericWktArray<i64> = to_wkt(&wkt_arr3).unwrap();
912 let wkt_arr5: GenericWktArray<i32> = to_wkt(&wkt_arr4).unwrap();
913 assert_eq!(wkt_arr, wkt_arr5);
914 }
915
916 #[test]
918 fn test_round_trip_wkb_point() {
919 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
920 for dim in [
921 Dimension::XY,
922 Dimension::XYZ,
923 Dimension::XYM,
924 Dimension::XYZM,
925 ] {
926 let arr = test::point::array(coord_type, dim);
927
928 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
929 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
930 assert_eq!(&arr, arr2.as_point());
931
932 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
933 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
934 assert_eq!(&arr, arr3.as_point());
935 }
936 }
937 }
938
939 #[test]
940 fn test_round_trip_wkb_linestring() {
941 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
942 for dim in [
943 Dimension::XY,
944 Dimension::XYZ,
945 Dimension::XYM,
946 Dimension::XYZM,
947 ] {
948 let arr = test::linestring::array(coord_type, dim);
949
950 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
951 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
952 assert_eq!(&arr, arr2.as_line_string());
953
954 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
955 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
956 assert_eq!(&arr, arr3.as_line_string());
957 }
958 }
959 }
960
961 #[test]
962 fn test_round_trip_wkb_polygon() {
963 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
964 for dim in [
965 Dimension::XY,
966 Dimension::XYZ,
967 Dimension::XYM,
968 Dimension::XYZM,
969 ] {
970 let arr = test::polygon::array(coord_type, dim);
971
972 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
973 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
974 assert_eq!(&arr, arr2.as_polygon());
975
976 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
977 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
978 assert_eq!(&arr, arr3.as_polygon());
979 }
980 }
981 }
982
983 #[test]
984 fn test_round_trip_wkb_multipoint() {
985 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
986 for dim in [
987 Dimension::XY,
988 Dimension::XYZ,
989 Dimension::XYM,
990 Dimension::XYZM,
991 ] {
992 let arr = test::multipoint::array(coord_type, dim);
993
994 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
995 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
996 assert_eq!(&arr, arr2.as_multi_point());
997
998 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
999 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1000 assert_eq!(&arr, arr3.as_multi_point());
1001 }
1002 }
1003 }
1004
1005 #[test]
1006 fn test_round_trip_wkb_multilinestring() {
1007 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1008 for dim in [
1009 Dimension::XY,
1010 Dimension::XYZ,
1011 Dimension::XYM,
1012 Dimension::XYZM,
1013 ] {
1014 let arr = test::multilinestring::array(coord_type, dim);
1015
1016 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
1017 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
1018 assert_eq!(&arr, arr2.as_multi_line_string());
1019
1020 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
1021 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1022 assert_eq!(&arr, arr3.as_multi_line_string());
1023 }
1024 }
1025 }
1026
1027 #[test]
1028 fn test_round_trip_wkb_multipolygon() {
1029 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1030 for dim in [
1031 Dimension::XY,
1032 Dimension::XYZ,
1033 Dimension::XYM,
1034 Dimension::XYZM,
1035 ] {
1036 let arr = test::multipolygon::array(coord_type, dim);
1037
1038 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
1039 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
1040 assert_eq!(&arr, arr2.as_multi_polygon());
1041
1042 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
1043 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1044 assert_eq!(&arr, arr3.as_multi_polygon());
1045 }
1046 }
1047 }
1048
1049 #[test]
1050 fn test_round_trip_wkb_geometrycollection() {
1051 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1052 for dim in [
1053 Dimension::XY,
1054 Dimension::XYZ,
1055 Dimension::XYM,
1056 Dimension::XYZM,
1057 ] {
1058 let arr = test::geometrycollection::array(coord_type, dim, false);
1059
1060 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
1061 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
1062 assert_eq!(&arr, arr2.as_geometry_collection());
1063
1064 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
1065 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1066 assert_eq!(&arr, arr3.as_geometry_collection());
1067 }
1068 }
1069 }
1070
1071 #[test]
1072 fn test_round_trip_wkb_geometry() {
1073 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1074 let arr = test::geometry::array(coord_type, false);
1075
1076 let wkb_arr = to_wkb::<i32>(&arr).unwrap();
1077 let arr2 = from_wkb(&wkb_arr, arr.data_type().clone()).unwrap();
1078 assert_eq!(&arr, arr2.as_geometry());
1079
1080 let wkb_arr2 = to_wkb::<i64>(&arr).unwrap();
1081 let arr3 = from_wkb(&wkb_arr2, arr.data_type().clone()).unwrap();
1082 assert_eq!(&arr, arr3.as_geometry());
1083 }
1084 }
1085
1086 #[test]
1088 fn test_round_trip_wkt_point() {
1089 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1090 for dim in [
1091 Dimension::XY,
1092 Dimension::XYZ,
1093 Dimension::XYM,
1094 Dimension::XYZM,
1095 ] {
1096 let arr = test::point::array(coord_type, dim);
1097
1098 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1099 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1100 assert_eq!(&arr, arr2.as_point());
1101
1102 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1103 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1104 assert_eq!(&arr, arr3.as_point());
1105 }
1106 }
1107 }
1108
1109 #[test]
1110 fn test_round_trip_wkt_linestring() {
1111 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1112 for dim in [
1113 Dimension::XY,
1114 Dimension::XYZ,
1115 Dimension::XYM,
1116 Dimension::XYZM,
1117 ] {
1118 let arr = test::linestring::array(coord_type, dim);
1119
1120 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1121 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1122 assert_eq!(&arr, arr2.as_line_string());
1123
1124 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1125 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1126 assert_eq!(&arr, arr3.as_line_string());
1127 }
1128 }
1129 }
1130
1131 #[test]
1132 fn test_round_trip_wkt_polygon() {
1133 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1134 for dim in [
1135 Dimension::XY,
1136 Dimension::XYZ,
1137 Dimension::XYM,
1138 Dimension::XYZM,
1139 ] {
1140 let arr = test::polygon::array(coord_type, dim);
1141
1142 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1143 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1144 assert_eq!(&arr, arr2.as_polygon());
1145
1146 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1147 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1148 assert_eq!(&arr, arr3.as_polygon());
1149 }
1150 }
1151 }
1152
1153 #[test]
1154 fn test_round_trip_wkt_multipoint() {
1155 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1156 for dim in [
1157 Dimension::XY,
1158 Dimension::XYZ,
1159 Dimension::XYM,
1160 Dimension::XYZM,
1161 ] {
1162 let arr = test::multipoint::array(coord_type, dim);
1163
1164 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1165 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1166 assert_eq!(&arr, arr2.as_multi_point());
1167
1168 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1169 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1170 assert_eq!(&arr, arr3.as_multi_point());
1171 }
1172 }
1173 }
1174
1175 #[test]
1176 fn test_round_trip_wkt_multilinestring() {
1177 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1178 for dim in [
1179 Dimension::XY,
1180 Dimension::XYZ,
1181 Dimension::XYM,
1182 Dimension::XYZM,
1183 ] {
1184 let arr = test::multilinestring::array(coord_type, dim);
1185
1186 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1187 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1188 assert_eq!(&arr, arr2.as_multi_line_string());
1189
1190 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1191 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1192 assert_eq!(&arr, arr3.as_multi_line_string());
1193 }
1194 }
1195 }
1196
1197 #[test]
1198 fn test_round_trip_wkt_multipolygon() {
1199 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1200 for dim in [
1201 Dimension::XY,
1202 Dimension::XYZ,
1203 Dimension::XYM,
1204 Dimension::XYZM,
1205 ] {
1206 let arr = test::multipolygon::array(coord_type, dim);
1207
1208 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1209 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1210 assert_eq!(&arr, arr2.as_multi_polygon());
1211
1212 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1213 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1214 assert_eq!(&arr, arr3.as_multi_polygon());
1215 }
1216 }
1217 }
1218
1219 #[test]
1220 fn test_round_trip_wkt_geometrycollection() {
1221 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1222 for dim in [
1223 Dimension::XY,
1224 Dimension::XYZ,
1225 Dimension::XYM,
1226 Dimension::XYZM,
1227 ] {
1228 let arr = test::geometrycollection::array(coord_type, dim, false);
1229
1230 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1231 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1232 assert_eq!(&arr, arr2.as_geometry_collection());
1233
1234 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1235 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1236 assert_eq!(&arr, arr3.as_geometry_collection());
1237 }
1238 }
1239 }
1240
1241 #[test]
1242 fn test_round_trip_wkt_geometry() {
1243 for coord_type in [CoordType::Interleaved, CoordType::Separated] {
1244 let arr = test::geometry::array(coord_type, false);
1245
1246 let wkt_arr = to_wkt::<i32>(&arr).unwrap();
1247 let arr2 = from_wkt(&wkt_arr, arr.data_type().clone()).unwrap();
1248 assert_eq!(&arr, arr2.as_geometry());
1249
1250 let wkt_arr2 = to_wkt::<i64>(&arr).unwrap();
1251 let arr3 = from_wkt(&wkt_arr2, arr.data_type().clone()).unwrap();
1252 assert_eq!(&arr, arr3.as_geometry());
1253 }
1254 }
1255
1256 #[allow(dead_code)]
1258 fn _to_wkb_test_downcast_macro(
1259 arr: &dyn GeoArrowArray,
1260 ) -> GeoArrowResult<GenericWkbArray<i32>> {
1261 downcast_geoarrow_array!(arr, impl_to_wkb)
1262 }
1263
1264 fn impl_to_wkb<'a>(
1265 geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
1266 ) -> GeoArrowResult<GenericWkbArray<i32>> {
1267 let geoms = geo_arr
1268 .iter()
1269 .map(|x| x.transpose())
1270 .collect::<std::result::Result<Vec<_>, _>>()
1271 .unwrap();
1272 let wkb_type = WkbType::new(geo_arr.data_type().metadata().clone());
1273 Ok(WkbBuilder::from_nullable_geometries(geoms.as_slice(), wkb_type)?.finish())
1274 }
1275
1276 #[test]
1278 fn test_downcast_macro_with_param() {
1279 let arr =
1280 Arc::new(test::geometry::array(Default::default(), false)) as Arc<dyn GeoArrowArray>;
1281 let arr_ref = arr.as_ref();
1282 let x = downcast_geoarrow_array!(arr_ref, impl_inner_function_with_param, 1.0).unwrap();
1283 assert_eq!(x, 1.0);
1284 }
1285
1286 fn impl_inner_function_with_param<'a>(
1287 _geo_arr: &'a impl GeoArrowArrayAccessor<'a>,
1288 param: f64,
1289 ) -> GeoArrowResult<f64> {
1290 Ok(param)
1291 }
1292}