1use darling::{FromDeriveInput, FromField};
2use proc_macro::TokenStream;
3use quote::{format_ident, quote};
4use syn::{DeriveInput, Ident, PathArguments, Type, parse_macro_input, spanned::Spanned};
5
6#[derive(Clone, Copy, Debug)]
7enum GeometryKind {
8 Point,
9 LineString,
10 Polygon,
11 MultiPoint,
12 MultiLineString,
13 MultiPolygon,
14 Geometry,
15 GeometryCollection,
16}
17
18#[derive(FromDeriveInput, Debug)]
20#[darling(attributes(geo), forward_attrs(allow, doc, cfg))]
21struct GeoParquetOpts {
22 ident: Ident,
23 data: darling::ast::Data<(), GeoFieldOpts>,
24}
25
26#[derive(FromField, Debug)]
28#[darling(attributes(geo), forward_attrs(allow, doc, cfg))]
29struct GeoFieldOpts {
30 ident: Option<Ident>,
31 ty: Type,
32
33 #[darling(default)]
35 name: Option<String>,
36
37 #[darling(default)]
39 geometry: bool,
40
41 #[darling(default)]
43 dim: Option<String>,
44}
45
46#[proc_macro_derive(GeoParquetRowData, attributes(geo))]
47pub fn derive_geo_parquet_row_data(input: TokenStream) -> TokenStream {
48 let input = parse_macro_input!(input as DeriveInput);
49 match impl_geoparquet_row_data(&input) {
50 Ok(ts) => ts,
51 Err(e) => e.to_compile_error().into(),
52 }
53}
54
55#[proc_macro_derive(GeoParquetRowStruct, attributes(geo))]
56pub fn derive_geo_parquet_row_struct(input: TokenStream) -> TokenStream {
57 let input = parse_macro_input!(input as DeriveInput);
58 match impl_geoparquet_row_struct(&input) {
59 Ok(ts) => ts,
60 Err(e) => e.to_compile_error().into(),
61 }
62}
63
64fn impl_geoparquet_row_data(input: &DeriveInput) -> syn::Result<TokenStream> {
65 let opts = GeoParquetOpts::from_derive_input(input).map_err(|e| syn::Error::from(e))?;
67
68 let struct_ident = &opts.ident;
69
70 let fields = match &opts.data {
71 darling::ast::Data::Struct(fields) => fields,
72 _ => {
73 return Err(syn::Error::new(
74 input.span(),
75 "GeoParquetRowData supports only structs",
76 ));
77 }
78 };
79
80 struct FieldInfo {
81 ident: Ident,
82 col_name: String,
83 ty: syn::Type,
84 is_option: bool,
85 is_geometry: bool,
86 geom_kind: Option<GeometryKind>,
87 dim: Option<String>, }
89
90 let mut finfos: Vec<FieldInfo> = Vec::new();
91 let mut geom_count = 0usize;
92
93 for field_opts in &fields.fields {
94 let ident = field_opts.ident.clone().ok_or_else(|| {
95 syn::Error::new(
96 field_opts.ty.span(),
97 "GeoParquetRowData requires named fields",
98 )
99 })?;
100
101 let col_name = field_opts.name.clone().unwrap_or_else(|| ident.to_string());
103
104 let is_geometry = field_opts.geometry;
106 let dim = field_opts.dim.clone();
107
108 let (is_option, inner_ty) = match option_inner(&field_opts.ty) {
110 Some(t) => (true, t),
111 None => (false, &field_opts.ty),
112 };
113
114 let detected_kind = geometry_kind(inner_ty);
116 let is_geometry = is_geometry || detected_kind.is_some();
117
118 if is_geometry {
119 geom_count += 1;
120 }
121
122 finfos.push(FieldInfo {
123 ident,
124 col_name,
125 ty: inner_ty.clone(),
126 is_option,
127 is_geometry,
128 geom_kind: detected_kind,
129 dim,
130 });
131 }
132
133 if geom_count == 0 {
134 return Err(syn::Error::new(
135 input.span(),
136 "No geometry field found. Mark one with #[geo(geometry)] or use a type like geo_types::Point<f64>, LineString<f64>, Polygon<f64>, MultiPoint<f64>, MultiLineString<f64>, MultiPolygon<f64>, Geometry<f64>, or GeometryCollection<f64>.",
137 ));
138 }
139 if geom_count > 1 {
140 return Err(syn::Error::new(
141 input.span(),
142 "Multiple geometry fields found; currently only one geometry field is supported.",
143 ));
144 }
145
146 for fi in &finfos {
148 if fi.is_geometry && fi.geom_kind.is_none() {
149 return Err(syn::Error::new(
150 fi.ty.span(),
151 "Unsupported geometry type. Expected geo_types::Point<f64>, LineString<f64>, Polygon<f64>, MultiPoint<f64>, MultiLineString<f64>, MultiPolygon<f64>, Geometry<f64>, or GeometryCollection<f64>.",
152 ));
153 }
154 }
155
156 let mut schema_field_tokens = Vec::new();
158 let mut array_expr_tokens = Vec::new();
159
160 let geom_type_ident = format_ident!("__gp_geom_type");
162 let geom_setup_tokens = |kind: GeometryKind,
163 dim_string: Option<&str>|
164 -> proc_macro2::TokenStream {
165 let dim_expr = match dim_string.unwrap_or("XY") {
166 "XYZ" => quote!(::geoparquet_batch_writer::__dep::geoarrow_schema::Dimension::XYZ),
167 "XYM" => quote!(::geoparquet_batch_writer::__dep::geoarrow_schema::Dimension::XYM),
168 _ => quote!(::geoparquet_batch_writer::__dep::geoarrow_schema::Dimension::XY),
169 };
170 let ty_ctor_two = match kind {
171 GeometryKind::Point => Some(quote!(
172 ::geoparquet_batch_writer::__dep::geoarrow_schema::PointType::new
173 )),
174 GeometryKind::LineString => Some(quote!(
175 ::geoparquet_batch_writer::__dep::geoarrow_schema::LineStringType::new
176 )),
177 GeometryKind::Polygon => Some(quote!(
178 ::geoparquet_batch_writer::__dep::geoarrow_schema::PolygonType::new
179 )),
180 GeometryKind::MultiPoint => Some(quote!(
181 ::geoparquet_batch_writer::__dep::geoarrow_schema::MultiPointType::new
182 )),
183 GeometryKind::MultiLineString => Some(quote!(
184 ::geoparquet_batch_writer::__dep::geoarrow_schema::MultiLineStringType::new
185 )),
186 GeometryKind::MultiPolygon => Some(quote!(
187 ::geoparquet_batch_writer::__dep::geoarrow_schema::MultiPolygonType::new
188 )),
189 GeometryKind::Geometry => None,
190 GeometryKind::GeometryCollection => None,
191 };
192 let one_arg_ctor = match kind {
193 GeometryKind::Geometry => Some(quote!(
194 ::geoparquet_batch_writer::__dep::geoarrow_schema::GeometryType::new
195 )),
196 GeometryKind::GeometryCollection => Some(quote!(
197 ::geoparquet_batch_writer::__dep::geoarrow_schema::GeometryCollectionType::new
198 )),
199 _ => None,
200 };
201
202 if let Some(ctor) = ty_ctor_two {
203 quote! {
204 let #geom_type_ident = {
205 let dim = #dim_expr;
206 #ctor(dim, ::std::sync::Arc::new(::std::default::Default::default()))
207 };
208 }
209 } else if let Some(ctor1) = one_arg_ctor {
210 quote! {
211 let #geom_type_ident = {
212 #ctor1(::std::sync::Arc::new(::std::default::Default::default()))
213 };
214 }
215 } else {
216 quote! {
218 let #geom_type_ident = {
219 let dim = #dim_expr;
220 ::geoparquet_batch_writer::__dep::geoarrow_schema::GeometryType::new(::std::sync::Arc::new(::std::default::Default::default()))
221 };
222 }
223 }
224 };
225
226 let mut geometry_init_tokens: Option<proc_macro2::TokenStream> = None;
228
229 for (idx, fi) in finfos.iter().enumerate() {
230 if fi.is_geometry {
231 let col_name_lit = syn::LitStr::new(&fi.col_name, fi.ident.span());
232 let is_option = fi.is_option;
233 let kind = fi.geom_kind.unwrap_or(GeometryKind::Geometry);
235
236 schema_field_tokens.push(quote! {
238 #geom_type_ident.to_field(#col_name_lit, #is_option)
239 });
240
241 let b_ident = format_ident!("__gp_geom_builder");
243 let arr_ident = format_ident!("__gp_arr_{}", idx);
244 let ident = &fi.ident;
245
246 let (builder_path, push_method_ident) = match kind {
247 GeometryKind::Point => (
248 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::PointBuilder),
249 format_ident!("push_point"),
250 ),
251 GeometryKind::LineString => (
252 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::LineStringBuilder),
253 format_ident!("push_line_string"),
254 ),
255 GeometryKind::Polygon => (
256 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::PolygonBuilder),
257 format_ident!("push_polygon"),
258 ),
259 GeometryKind::MultiPoint => (
260 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::MultiPointBuilder),
261 format_ident!("push_multi_point"),
262 ),
263 GeometryKind::MultiLineString => (
264 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::MultiLineStringBuilder),
265 format_ident!("push_multi_line_string"),
266 ),
267 GeometryKind::MultiPolygon => (
268 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::MultiPolygonBuilder),
269 format_ident!("push_multi_polygon"),
270 ),
271 GeometryKind::Geometry => (
272 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::GeometryBuilder),
273 format_ident!("push_geometry"),
274 ),
275 GeometryKind::GeometryCollection => (
276 quote!(::geoparquet_batch_writer::__dep::geoarrow_array::builder::GeometryCollectionBuilder),
277 format_ident!("push_geometry_collection"),
278 ),
279 };
280
281 let push_tokens = if fi.is_option {
283 quote! {
284 for row in rows {
285 if let Some(g) = row.#ident.as_ref() {
286 let _ = #b_ident.#push_method_ident(Some(g));
287 } else {
288 let _ = #b_ident.push_null();
290 }
291 }
292 }
293 } else {
294 quote! {
295 for row in rows {
296 let g = &row.#ident;
297 let _ = #b_ident.#push_method_ident(Some(g));
298 }
299 }
300 };
301
302 array_expr_tokens.push(quote! {{
303 use ::geoparquet_batch_writer::__dep::geoarrow_array::GeoArrowArray as _;
304 let mut #b_ident = #builder_path::new(#geom_type_ident.clone());
305 #push_tokens
306 let #arr_ident = ::std::sync::Arc::new(#b_ident.finish().into_array_ref());
307 #arr_ident
308 }});
309
310 geometry_init_tokens = Some(geom_setup_tokens(kind, fi.dim.as_deref()));
312 } else {
313 let dt = arrow_datatype(&fi.ty)?;
315 let (array_ty, from_tokens) = array_ctor(&fi.ty, fi.is_option)?;
316 let col_name_lit = syn::LitStr::new(&fi.col_name, fi.ident.span());
317 let is_option = fi.is_option;
318 schema_field_tokens.push(quote! {
319 ::geoparquet_batch_writer::__dep::arrow_schema::Field::new(#col_name_lit, #dt, #is_option)
320 });
321 let arr_ident = format_ident!("__gp_arr_{}", idx);
322
323 let map_expr = value_mapper(&fi.ty, &fi.ident, fi.is_option);
325
326 array_expr_tokens.push(quote! {{
327 let it = rows.iter().map(#map_expr);
328 let arr: ::std::sync::Arc<#array_ty> = #from_tokens;
329 let #arr_ident: ::std::sync::Arc<dyn ::geoparquet_batch_writer::__dep::arrow_array::Array> = arr;
330 #arr_ident
331 }});
332 }
333 }
334
335 let schema_vec_tokens = quote! {
336 {
337 ::std::sync::Arc::new(::geoparquet_batch_writer::__dep::arrow_schema::Schema::new(vec![
338 #(#schema_field_tokens),*
339 ]))
340 }
341 };
342
343 let arrays_vec_tokens = quote! {
344 {
345 ::std::result::Result::Ok(vec![
346 #(#array_expr_tokens),*
347 ])
348 }
349 };
350
351 let expanded = quote! {
352 impl ::geoparquet_batch_writer::GeoParquetRowData for #struct_ident
353 where Self: Send + Sync
354 {
355 fn schema() -> ::std::sync::Arc<::geoparquet_batch_writer::__dep::arrow_schema::Schema> {
356 #geometry_init_tokens
357 #schema_vec_tokens
358 }
359
360 fn to_arrays(rows: &[Self]) -> ::geoparquet_batch_writer::__dep::Result<Vec<::std::sync::Arc<dyn ::geoparquet_batch_writer::__dep::arrow_array::Array>>> {
361 #geometry_init_tokens
362 #arrays_vec_tokens
363 }
364 }
365 };
366
367 Ok(expanded.into())
368}
369
370fn impl_geoparquet_row_struct(input: &DeriveInput) -> syn::Result<TokenStream> {
371 let opts = GeoParquetOpts::from_derive_input(input).map_err(|e| syn::Error::from(e))?;
373
374 let struct_ident = &opts.ident;
375
376 let fields = match &opts.data {
377 darling::ast::Data::Struct(fields) => fields,
378 _ => {
379 return Err(syn::Error::new(
380 input.span(),
381 "GeoParquetRowStruct supports only structs",
382 ));
383 }
384 };
385
386 struct FieldInfo {
387 ident: Ident,
388 col_name: String,
389 ty: syn::Type,
390 is_option: bool,
391 }
392
393 let mut finfos: Vec<FieldInfo> = Vec::new();
394
395 for field_opts in &fields.fields {
396 let ident = field_opts.ident.clone().ok_or_else(|| {
397 syn::Error::new(
398 field_opts.ty.span(),
399 "GeoParquetRowStruct requires named fields",
400 )
401 })?;
402
403 let col_name = field_opts.name.clone().unwrap_or_else(|| ident.to_string());
405
406 let (is_option, inner_ty) = match option_inner(&field_opts.ty) {
408 Some(t) => (true, t),
409 None => (false, &field_opts.ty),
410 };
411
412 finfos.push(FieldInfo {
413 ident,
414 col_name,
415 ty: inner_ty.clone(),
416 is_option,
417 });
418 }
419
420 let mut struct_field_tokens = Vec::new();
422
423 for fi in &finfos {
424 let col_name_lit = syn::LitStr::new(&fi.col_name, fi.ident.span());
425 let ty = &fi.ty;
426 let is_option = fi.is_option;
427
428 struct_field_tokens.push(quote! {
429 ::geoparquet_batch_writer::__dep::arrow_schema::Field::new(
430 #col_name_lit,
431 <#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::data_type(),
432 #is_option
433 )
434 });
435 }
436
437 let mut field_array_tokens_iter_values = Vec::new();
439 let mut field_array_tokens_iter = Vec::new();
440
441 for (idx, fi) in finfos.iter().enumerate() {
442 let ident = &fi.ident;
443 let ty = &fi.ty;
444 let is_option = fi.is_option;
445 let arr_ident = format_ident!("__gp_arr_{}", idx);
446
447 if is_option {
448 field_array_tokens_iter_values.push(quote! {
450 let field_iter = values.iter().map(|r: &Self| r.#ident.clone());
451 let #arr_ident = <#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter(field_iter);
452 });
453 field_array_tokens_iter.push(quote! {
454 let field_iter = values.iter().map(|r: &Self| r.#ident.clone());
455 let #arr_ident = <#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter(field_iter);
456 });
457 } else {
458 field_array_tokens_iter_values.push(quote! {
460 let field_iter = values.iter().map(|r: &Self| r.#ident.clone());
461 let #arr_ident = <#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter_values(field_iter);
462 });
463 field_array_tokens_iter.push(quote! {
464 let field_iter = values.iter().map(|r: &Self| r.#ident.clone());
465 let #arr_ident = <#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter_values(field_iter);
466 });
467 }
468 }
469
470 let field_array_refs: Vec<_> = (0..finfos.len())
471 .map(|idx| format_ident!("__gp_arr_{}", idx))
472 .collect();
473
474 let expanded = quote! {
475 impl ::geoparquet_batch_writer::__dep::ArrowDataType for #struct_ident
476 where Self: Send + Sync + Clone + 'static
477 {
478 type Array = ::geoparquet_batch_writer::__dep::arrow_array::StructArray;
479
480 fn data_type() -> ::geoparquet_batch_writer::__dep::arrow_schema::DataType {
481 ::geoparquet_batch_writer::__dep::arrow_schema::DataType::Struct(
482 ::geoparquet_batch_writer::__dep::arrow_schema::Fields::from(vec![
483 #(#struct_field_tokens),*
484 ])
485 )
486 }
487
488 fn from_iter_values<I>(iter: I) -> ::std::sync::Arc<Self::Array>
489 where
490 I: IntoIterator<Item = Self>,
491 {
492 let values: Vec<Self> = iter.into_iter().collect();
493 #(#field_array_tokens_iter_values)*
494
495 let field_arrays: Vec<::std::sync::Arc<dyn ::geoparquet_batch_writer::__dep::arrow_array::Array>> = vec![
496 #(#field_array_refs as ::std::sync::Arc<dyn ::geoparquet_batch_writer::__dep::arrow_array::Array>),*
497 ];
498
499 let fields = match Self::data_type() {
500 ::geoparquet_batch_writer::__dep::arrow_schema::DataType::Struct(fields) => fields,
501 _ => unreachable!(),
502 };
503
504 ::std::sync::Arc::new(
505 ::geoparquet_batch_writer::__dep::arrow_array::StructArray::new(
506 fields,
507 field_arrays,
508 None
509 )
510 )
511 }
512
513 fn from_iter<I>(iter: I) -> ::std::sync::Arc<Self::Array>
514 where
515 I: IntoIterator<Item = Option<Self>>,
516 {
517 let collected: Vec<_> = iter.into_iter().collect();
518 let len = collected.len();
519
520 let mut validity = ::geoparquet_batch_writer::__dep::arrow_array::builder::BooleanBufferBuilder::new(len);
522 let values: Vec<Self> = collected.into_iter().map(|opt| {
523 match opt {
524 Some(val) => {
525 validity.append(true);
526 val
527 },
528 None => {
529 validity.append(false);
530 ::std::default::Default::default()
533 }
534 }
535 }).collect();
536
537 let validity_buffer = validity.finish();
538 #(#field_array_tokens_iter)*
539
540 let field_arrays: Vec<::std::sync::Arc<dyn ::geoparquet_batch_writer::__dep::arrow_array::Array>> = vec![
541 #(#field_array_refs as ::std::sync::Arc<dyn ::geoparquet_batch_writer::__dep::arrow_array::Array>),*
542 ];
543
544 let fields = match Self::data_type() {
545 ::geoparquet_batch_writer::__dep::arrow_schema::DataType::Struct(fields) => fields,
546 _ => unreachable!(),
547 };
548
549 ::std::sync::Arc::new(
550 ::geoparquet_batch_writer::__dep::arrow_array::StructArray::new(
551 fields,
552 field_arrays,
553 Some(validity_buffer.into())
554 )
555 )
556 }
557 }
558 };
559
560 Ok(expanded.into())
561}
562
563fn option_inner(ty: &Type) -> Option<&Type> {
564 if let Type::Path(tp) = ty {
565 if let Some(seg) = tp.path.segments.last() {
566 if seg.ident == "Option" {
567 if let PathArguments::AngleBracketed(args) = &seg.arguments {
568 if let Some(syn::GenericArgument::Type(inner)) = args.args.first() {
569 return Some(inner);
570 }
571 }
572 }
573 }
574 }
575 None
576}
577
578fn vec_inner(ty: &Type) -> Option<&Type> {
579 if let Type::Path(tp) = ty {
580 if let Some(seg) = tp.path.segments.last() {
581 if seg.ident == "Vec" {
582 if let PathArguments::AngleBracketed(args) = &seg.arguments {
583 if let Some(syn::GenericArgument::Type(inner)) = args.args.first() {
584 return Some(inner);
585 }
586 }
587 }
588 }
589 }
590 None
591}
592
593fn geometry_kind(ty: &Type) -> Option<GeometryKind> {
594 if let Type::Path(tp) = ty {
596 if let Some(seg) = tp.path.segments.last() {
597 let name = seg.ident.to_string();
598 if let PathArguments::AngleBracketed(args) = &seg.arguments {
599 if let Some(syn::GenericArgument::Type(Type::Path(inner))) = args.args.first() {
600 if let Some(seg2) = inner.path.segments.last() {
601 if seg2.ident == "f64" {
602 return match name.as_str() {
603 "Point" => Some(GeometryKind::Point),
604 "LineString" => Some(GeometryKind::LineString),
605 "Polygon" => Some(GeometryKind::Polygon),
606 "MultiPoint" => Some(GeometryKind::MultiPoint),
607 "MultiLineString" => Some(GeometryKind::MultiLineString),
608 "MultiPolygon" => Some(GeometryKind::MultiPolygon),
609 "Geometry" => Some(GeometryKind::Geometry),
610 "GeometryCollection" => Some(GeometryKind::GeometryCollection),
611 _ => None,
612 };
613 }
614 }
615 }
616 }
617 }
618 }
619 None
620}
621
622fn arrow_datatype(ty: &Type) -> syn::Result<proc_macro2::TokenStream> {
623 if let Some(inner_ty) = vec_inner(ty) {
625 let inner_dt = arrow_datatype(inner_ty)?;
626 return Ok(quote!(
627 ::geoparquet_batch_writer::__dep::arrow_schema::DataType::List(
628 ::std::sync::Arc::new(
629 ::geoparquet_batch_writer::__dep::arrow_schema::Field::new(
630 "item",
631 #inner_dt,
632 true
633 )
634 )
635 )
636 ));
637 }
638
639 Ok(quote!(<#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::data_type()))
641}
642
643fn array_ctor(
644 ty: &Type,
645 is_option: bool,
646) -> syn::Result<(proc_macro2::TokenStream, proc_macro2::TokenStream)> {
647 if let Some(inner_ty) = vec_inner(ty) {
649 let inner_type_name = type_name(inner_ty);
650
651 let primitive_builder = match inner_type_name.as_str() {
653 "u64" => Some((
654 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::UInt64Builder),
655 quote!(values.append_value(*val)),
656 )),
657 "i64" => Some((
658 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::Int64Builder),
659 quote!(values.append_value(*val)),
660 )),
661 "u32" => Some((
662 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::UInt32Builder),
663 quote!(values.append_value(*val)),
664 )),
665 "i32" => Some((
666 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::Int32Builder),
667 quote!(values.append_value(*val)),
668 )),
669 "f64" => Some((
670 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::Float64Builder),
671 quote!(values.append_value(*val)),
672 )),
673 "f32" => Some((
674 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::Float32Builder),
675 quote!(values.append_value(*val)),
676 )),
677 "bool" => Some((
678 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::BooleanBuilder),
679 quote!(values.append_value(*val)),
680 )),
681 "String" => Some((
682 quote!(::geoparquet_batch_writer::__dep::arrow_array::builder::StringBuilder),
683 quote!(values.append_value(val)),
684 )),
685 _ => None,
686 };
687
688 if let Some((values_builder_type, values_append)) = primitive_builder {
689 let list_construction = if is_option {
690 quote! {
691 {
692 let mut builder = ::geoparquet_batch_writer::__dep::arrow_array::builder::ListBuilder::new(#values_builder_type::new());
693 for opt_vec in it {
694 if let Some(vec_val) = opt_vec {
695 let values = builder.values();
696 for val in vec_val {
697 #values_append;
698 }
699 builder.append(true);
700 } else {
701 builder.append(false);
702 }
703 }
704 builder.finish()
705 }
706 }
707 } else {
708 quote! {
709 {
710 let mut builder = ::geoparquet_batch_writer::__dep::arrow_array::builder::ListBuilder::new(#values_builder_type::new());
711 for vec_val in it {
712 let values = builder.values();
713 for val in vec_val {
714 #values_append;
715 }
716 builder.append(true);
717 }
718 builder.finish()
719 }
720 }
721 };
722
723 return Ok((
724 quote!(::geoparquet_batch_writer::__dep::arrow_array::ListArray),
725 quote! { ::std::sync::Arc::new(#list_construction) },
726 ));
727 }
728
729 let list_construction = if is_option {
731 quote! {
732 {
733 let all_list_values: Vec<_> = it.collect();
735
736 let mut all_values = Vec::new();
738 let mut validity = ::geoparquet_batch_writer::__dep::arrow_array::builder::BooleanBufferBuilder::new(all_list_values.len());
739
740 for list_opt in &all_list_values {
741 match list_opt {
742 Some(vec_val) => {
743 validity.append(true);
744 all_values.extend(vec_val.iter().cloned());
745 }
746 None => {
747 validity.append(false);
748 }
750 }
751 }
752
753 let values_array = <#inner_ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter_values(all_values);
754 let validity_buffer = validity.finish();
755
756 ::geoparquet_batch_writer::__dep::arrow_array::ListArray::try_new(
758 ::std::sync::Arc::new(::geoparquet_batch_writer::__dep::arrow_schema::Field::new(
759 "item",
760 <#inner_ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::data_type(),
761 true
762 )),
763 ::geoparquet_batch_writer::__dep::arrow_buffer::OffsetBuffer::from_lengths(
764 all_list_values.iter().map(|opt| {
765 opt.as_ref().map(|v| v.len()).unwrap_or(0)
766 })
767 ),
768 values_array,
769 Some(validity_buffer.into())
770 ).unwrap()
771 }
772 }
773 } else {
774 quote! {
775 {
776 let all_vecs: Vec<_> = it.collect();
777 let mut all_values = Vec::new();
778
779 for vec_val in &all_vecs {
780 all_values.extend(vec_val.iter().cloned());
781 }
782
783 let values_array = <#inner_ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter_values(all_values);
784
785 ::geoparquet_batch_writer::__dep::arrow_array::ListArray::try_new(
786 ::std::sync::Arc::new(::geoparquet_batch_writer::__dep::arrow_schema::Field::new(
787 "item",
788 <#inner_ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::data_type(),
789 true
790 )),
791 ::geoparquet_batch_writer::__dep::arrow_buffer::OffsetBuffer::from_lengths(
792 all_vecs.iter().map(|v| v.len())
793 ),
794 values_array,
795 None
796 ).unwrap()
797 }
798 }
799 };
800 return Ok((
801 quote!(::geoparquet_batch_writer::__dep::arrow_array::ListArray),
802 quote! { ::std::sync::Arc::new(#list_construction) },
803 ));
804 }
805
806 let arr_ty = quote!(<#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::Array);
808 let from = if is_option {
809 quote!(<#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter(it))
810 } else {
811 quote!(<#ty as ::geoparquet_batch_writer::__dep::ArrowDataType>::from_iter_values(it))
812 };
813 Ok((arr_ty, from))
814}
815
816fn value_mapper(ty: &Type, ident: &Ident, is_option: bool) -> proc_macro2::TokenStream {
817 if vec_inner(ty).is_some() {
819 if is_option {
820 quote!(|r: &Self| r.#ident.as_ref())
821 } else {
822 quote!(|r: &Self| &r.#ident)
823 }
824 } else {
825 let t = type_name(ty);
826 if t == "String" {
827 if is_option {
828 quote!(|r: &Self| r.#ident.as_ref().map(|s| s.clone()))
829 } else {
830 quote!(|r: &Self| r.#ident.clone())
831 }
832 } else if is_copy_scalar(&t) {
833 if is_option {
834 quote!(|r: &Self| r.#ident)
835 } else {
836 quote!(|r: &Self| r.#ident)
837 }
838 } else {
839 quote!(|r: &Self| r.#ident)
841 }
842 }
843}
844
845fn type_name(ty: &Type) -> String {
846 if let Type::Path(tp) = ty {
847 if let Some(seg) = tp.path.segments.last() {
848 return seg.ident.to_string();
849 }
850 }
851 format!("{}", quote!(#ty))
852}
853
854fn is_copy_scalar(name: &str) -> bool {
855 matches!(name, "u64" | "i64" | "u32" | "i32" | "f64" | "f32" | "bool")
856}