typed_arrow/bridge/
map.rs

1//! `Map` and `OrderedMap` bindings.
2
3use std::{collections::BTreeMap, sync::Arc};
4
5use arrow_array::{builder::MapBuilder, MapArray};
6use arrow_schema::{DataType, Field};
7
8use super::ArrowBinding;
9
10/// Wrapper denoting an Arrow `MapArray` column with entries `(K, V)`.
11///
12/// - Keys are non-nullable by Arrow spec.
13/// - Values are non-nullable for `Map<K, V, SORTED>` and nullable for `Map<K, Option<V>, SORTED>`.
14/// - Column-level nullability is expressed with `Option<Map<...>>`.
15pub struct Map<K, V, const SORTED: bool = false>(Vec<(K, V)>);
16impl<K, V, const SORTED: bool> Map<K, V, SORTED> {
17    /// Construct a new map from a vector of `(key, value)` pairs.
18    #[inline]
19    #[must_use]
20    pub fn new(entries: Vec<(K, V)>) -> Self {
21        Self(entries)
22    }
23    /// Borrow the underlying `(key, value)` entries.
24    #[inline]
25    #[must_use]
26    pub fn entries(&self) -> &Vec<(K, V)> {
27        &self.0
28    }
29    /// Consume and return the underlying `(key, value)` entries.
30    #[inline]
31    #[must_use]
32    pub fn into_inner(self) -> Vec<(K, V)> {
33        self.0
34    }
35}
36
37impl<K, V, const SORTED: bool> From<Vec<(K, V)>> for Map<K, V, SORTED> {
38    /// Convert a vector of `(key, value)` pairs into a `Map`.
39    #[inline]
40    fn from(entries: Vec<(K, V)>) -> Self {
41        Self::new(entries)
42    }
43}
44
45impl<K, V, const SORTED: bool> std::iter::FromIterator<(K, V)> for Map<K, V, SORTED> {
46    /// Collect an iterator of `(key, value)` pairs into a `Map`.
47    #[inline]
48    fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
49        Self::new(iter.into_iter().collect())
50    }
51}
52
53impl<K, V, const SORTED: bool> ArrowBinding for Map<K, V, SORTED>
54where
55    K: ArrowBinding,
56    V: ArrowBinding,
57    <K as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
58    <V as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
59{
60    type Builder = MapBuilder<<K as ArrowBinding>::Builder, <V as ArrowBinding>::Builder>;
61    type Array = MapArray;
62    fn data_type() -> DataType {
63        let key_f = Field::new("keys", <K as ArrowBinding>::data_type(), false);
64        // MapBuilder names children `keys` and `values`; value field is nullable
65        let val_f = Field::new("values", <V as ArrowBinding>::data_type(), true);
66        let entries = DataType::Struct(vec![Arc::new(key_f), Arc::new(val_f)].into());
67        DataType::Map(Field::new("entries", entries, false).into(), SORTED)
68    }
69    fn new_builder(_capacity: usize) -> Self::Builder {
70        let kb = <K as ArrowBinding>::new_builder(0);
71        let vb = <V as ArrowBinding>::new_builder(0);
72        MapBuilder::new(None, kb, vb)
73    }
74    fn append_value(b: &mut Self::Builder, v: &Self) {
75        for (k, val) in &v.0 {
76            <K as ArrowBinding>::append_value(b.keys(), k);
77            <V as ArrowBinding>::append_value(b.values(), val);
78        }
79        let _ = b.append(true);
80    }
81    fn append_null(b: &mut Self::Builder) {
82        let _ = b.append(false);
83    }
84    fn finish(mut b: Self::Builder) -> Self::Array {
85        b.finish()
86    }
87}
88
89// Provide ArrowBinding for value-nullable variant via Option<V>
90impl<K, V, const SORTED: bool> ArrowBinding for Map<K, Option<V>, SORTED>
91where
92    K: ArrowBinding,
93    V: ArrowBinding,
94    <K as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
95    <V as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
96{
97    type Builder = MapBuilder<<K as ArrowBinding>::Builder, <V as ArrowBinding>::Builder>;
98    type Array = MapArray;
99    fn data_type() -> DataType {
100        let key_f = Field::new("keys", <K as ArrowBinding>::data_type(), false);
101        let val_f = Field::new("values", <V as ArrowBinding>::data_type(), true);
102        let entries = DataType::Struct(vec![Arc::new(key_f), Arc::new(val_f)].into());
103        DataType::Map(Field::new("entries", entries, false).into(), SORTED)
104    }
105    fn new_builder(_capacity: usize) -> Self::Builder {
106        let kb = <K as ArrowBinding>::new_builder(0);
107        let vb = <V as ArrowBinding>::new_builder(0);
108        MapBuilder::new(None, kb, vb)
109    }
110    fn append_value(b: &mut Self::Builder, v: &Self) {
111        for (k, val_opt) in &v.0 {
112            <K as ArrowBinding>::append_value(b.keys(), k);
113            match val_opt {
114                Some(val) => <V as ArrowBinding>::append_value(b.values(), val),
115                None => <V as ArrowBinding>::append_null(b.values()),
116            }
117        }
118        let _ = b.append(true);
119    }
120    fn append_null(b: &mut Self::Builder) {
121        let _ = b.append(false);
122    }
123    fn finish(mut b: Self::Builder) -> Self::Array {
124        b.finish()
125    }
126}
127
128/// Sorted-keys `Map`: entries sourced from `BTreeMap<K, V>`, declaring `keys_sorted = true`.
129/// Keys are non-nullable; the value field is nullable per `MapBuilder` semantics, but this
130/// wrapper does not write null values.
131pub struct OrderedMap<K, V>(BTreeMap<K, V>);
132impl<K, V> OrderedMap<K, V> {
133    /// Construct a new ordered-map from a `BTreeMap` (keys sorted).
134    #[inline]
135    #[must_use]
136    pub fn new(map: BTreeMap<K, V>) -> Self {
137        Self(map)
138    }
139    /// Borrow the underlying `BTreeMap`.
140    #[inline]
141    #[must_use]
142    pub fn map(&self) -> &BTreeMap<K, V> {
143        &self.0
144    }
145    /// Consume and return the underlying `BTreeMap`.
146    #[inline]
147    #[must_use]
148    pub fn into_inner(self) -> BTreeMap<K, V> {
149        self.0
150    }
151}
152
153impl<K, V> ArrowBinding for OrderedMap<K, V>
154where
155    K: ArrowBinding + Ord,
156    V: ArrowBinding,
157    <K as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
158    <V as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
159{
160    type Builder = MapBuilder<<K as ArrowBinding>::Builder, <V as ArrowBinding>::Builder>;
161    type Array = MapArray;
162    fn data_type() -> DataType {
163        let key_f = Field::new("keys", <K as ArrowBinding>::data_type(), false);
164        let val_f = Field::new("values", <V as ArrowBinding>::data_type(), true);
165        let entries = DataType::Struct(vec![Arc::new(key_f), Arc::new(val_f)].into());
166        DataType::Map(Field::new("entries", entries, false).into(), true)
167    }
168    fn new_builder(_capacity: usize) -> Self::Builder {
169        let kb = <K as ArrowBinding>::new_builder(0);
170        let vb = <V as ArrowBinding>::new_builder(0);
171        MapBuilder::new(None, kb, vb)
172    }
173    fn append_value(b: &mut Self::Builder, v: &Self) {
174        for (k, val) in &v.0 {
175            <K as ArrowBinding>::append_value(b.keys(), k);
176            <V as ArrowBinding>::append_value(b.values(), val);
177        }
178        let _ = b.append(true);
179    }
180    fn append_null(b: &mut Self::Builder) {
181        let _ = b.append(false);
182    }
183    fn finish(mut b: Self::Builder) -> Self::Array {
184        use arrow_array::Array;
185        use arrow_data::ArrayData;
186
187        let map_array = b.finish();
188
189        // MapBuilder always creates maps with sorted=false, so we need to manually update it
190        // Get the existing field and create a new DataType with sorted=true
191        let data = map_array.into_data();
192        let (field, _sorted) = match data.data_type() {
193            DataType::Map(f, _) => (f.clone(), true),
194            _ => unreachable!(),
195        };
196
197        // Reconstruct the MapArray with sorted=true flag
198        // All data is copied from the valid MapArray produced by MapBuilder
199        let new_data = ArrayData::builder(DataType::Map(field, true))
200            .len(data.len())
201            .buffers(data.buffers().to_vec())
202            .child_data(data.child_data().to_vec())
203            .nulls(data.nulls().cloned())
204            .build()
205            .expect("MapArray reconstruction should succeed - all data copied from valid array");
206
207        MapArray::from(new_data)
208    }
209}
210
211// Provide ArrowBinding for OrderedMap<K, Option<V>> mirroring the non-wrapper variant
212impl<K, V> ArrowBinding for OrderedMap<K, Option<V>>
213where
214    K: ArrowBinding + Ord,
215    V: ArrowBinding,
216    <K as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
217    <V as ArrowBinding>::Builder: arrow_array::builder::ArrayBuilder,
218{
219    type Builder = MapBuilder<<K as ArrowBinding>::Builder, <V as ArrowBinding>::Builder>;
220    type Array = MapArray;
221    fn data_type() -> DataType {
222        let key_f = Field::new("keys", <K as ArrowBinding>::data_type(), false);
223        let val_f = Field::new("values", <V as ArrowBinding>::data_type(), true);
224        let entries = DataType::Struct(vec![Arc::new(key_f), Arc::new(val_f)].into());
225        DataType::Map(Field::new("entries", entries, false).into(), true)
226    }
227    fn new_builder(_capacity: usize) -> Self::Builder {
228        let kb = <K as ArrowBinding>::new_builder(0);
229        let vb = <V as ArrowBinding>::new_builder(0);
230        MapBuilder::new(None, kb, vb)
231    }
232    fn append_value(b: &mut Self::Builder, v: &Self) {
233        for (k, val_opt) in &v.0 {
234            <K as ArrowBinding>::append_value(b.keys(), k);
235            match val_opt {
236                Some(val) => <V as ArrowBinding>::append_value(b.values(), val),
237                None => <V as ArrowBinding>::append_null(b.values()),
238            }
239        }
240        let _ = b.append(true);
241    }
242    fn append_null(b: &mut Self::Builder) {
243        let _ = b.append(false);
244    }
245    fn finish(mut b: Self::Builder) -> Self::Array {
246        use arrow_array::Array;
247        use arrow_data::ArrayData;
248
249        let map_array = b.finish();
250
251        // MapBuilder always creates maps with sorted=false, so we need to manually update it
252        // Get the existing field and create a new DataType with sorted=true
253        let data = map_array.into_data();
254        let (field, _sorted) = match data.data_type() {
255            DataType::Map(f, _) => (f.clone(), true),
256            _ => unreachable!(),
257        };
258
259        // Reconstruct the MapArray with sorted=true flag
260        // All data is copied from the valid MapArray produced by MapBuilder
261        let new_data = ArrayData::builder(DataType::Map(field, true))
262            .len(data.len())
263            .buffers(data.buffers().to_vec())
264            .child_data(data.child_data().to_vec())
265            .nulls(data.nulls().cloned())
266            .build()
267            .expect("MapArray reconstruction should succeed - all data copied from valid array");
268
269        MapArray::from(new_data)
270    }
271}
272
273/// Iterator over views of map entries (key-value pairs).
274#[cfg(feature = "views")]
275pub struct MapView<'a, K, V, const SORTED: bool = false>
276where
277    K: super::ArrowBindingView + 'static,
278    V: super::ArrowBindingView + 'static,
279{
280    keys_array: &'a <K as super::ArrowBindingView>::Array,
281    values_array: &'a <V as super::ArrowBindingView>::Array,
282    start: usize,
283    end: usize,
284}
285
286#[cfg(feature = "views")]
287impl<'a, K, V, const SORTED: bool> MapView<'a, K, V, SORTED>
288where
289    K: super::ArrowBindingView + 'static,
290    V: super::ArrowBindingView + 'static,
291{
292    fn new(
293        keys_array: &'a <K as super::ArrowBindingView>::Array,
294        values_array: &'a <V as super::ArrowBindingView>::Array,
295        start: usize,
296        end: usize,
297    ) -> Self {
298        Self {
299            keys_array,
300            values_array,
301            start,
302            end,
303        }
304    }
305
306    /// Get the number of entries in the map.
307    #[inline]
308    pub fn len(&self) -> usize {
309        self.end - self.start
310    }
311
312    /// Check if the map is empty.
313    #[inline]
314    pub fn is_empty(&self) -> bool {
315        self.start == self.end
316    }
317}
318
319#[cfg(feature = "views")]
320impl<'a, K, V, EK, EV, const SORTED: bool> TryFrom<MapView<'a, K, V, SORTED>> for Map<K, V, SORTED>
321where
322    K: super::ArrowBindingView + 'static,
323    V: super::ArrowBindingView + 'static,
324    K::View<'a>: TryInto<K, Error = EK>,
325    V::View<'a>: TryInto<V, Error = EV>,
326    EK: Into<crate::schema::ViewAccessError>,
327    EV: Into<crate::schema::ViewAccessError>,
328{
329    type Error = crate::schema::ViewAccessError;
330
331    fn try_from(view: MapView<'a, K, V, SORTED>) -> Result<Self, Self::Error> {
332        let mut entries = Vec::with_capacity(view.len());
333        for i in view.start..view.end {
334            let key_view = K::get_view(view.keys_array, i)?;
335            let value_view = V::get_view(view.values_array, i)?;
336            entries.push((
337                key_view.try_into().map_err(|e| e.into())?,
338                value_view.try_into().map_err(|e| e.into())?,
339            ));
340        }
341        Ok(Map::new(entries))
342    }
343}
344
345#[cfg(feature = "views")]
346impl<'a, K, V, const SORTED: bool> Iterator for MapView<'a, K, V, SORTED>
347where
348    K: super::ArrowBindingView + 'static,
349    V: super::ArrowBindingView + 'static,
350{
351    type Item = Result<(K::View<'a>, V::View<'a>), crate::schema::ViewAccessError>;
352
353    fn next(&mut self) -> Option<Self::Item> {
354        if self.start < self.end {
355            let result = K::get_view(self.keys_array, self.start).and_then(|key| {
356                V::get_view(self.values_array, self.start).map(|value| (key, value))
357            });
358            self.start += 1;
359            Some(result)
360        } else {
361            None
362        }
363    }
364
365    fn size_hint(&self) -> (usize, Option<usize>) {
366        let remaining = self.end - self.start;
367        (remaining, Some(remaining))
368    }
369}
370
371#[cfg(feature = "views")]
372impl<'a, K, V, const SORTED: bool> ExactSizeIterator for MapView<'a, K, V, SORTED>
373where
374    K: super::ArrowBindingView + 'static,
375    V: super::ArrowBindingView + 'static,
376{
377    fn len(&self) -> usize {
378        self.end - self.start
379    }
380}
381
382#[cfg(feature = "views")]
383impl<K, V, const SORTED: bool> super::ArrowBindingView for Map<K, V, SORTED>
384where
385    K: ArrowBinding + super::ArrowBindingView + 'static,
386    V: ArrowBinding + super::ArrowBindingView + 'static,
387{
388    type Array = arrow_array::MapArray;
389    type View<'a> = MapView<'a, K, V, SORTED>;
390
391    fn get_view(
392        array: &Self::Array,
393        index: usize,
394    ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
395        use arrow_array::Array;
396        if index >= array.len() {
397            return Err(crate::schema::ViewAccessError::OutOfBounds {
398                index,
399                len: array.len(),
400                field_name: None,
401            });
402        }
403        if array.is_null(index) {
404            return Err(crate::schema::ViewAccessError::UnexpectedNull {
405                index,
406                field_name: None,
407            });
408        }
409
410        let offsets = array.value_offsets();
411        let start = offsets[index] as usize;
412        let end = offsets[index + 1] as usize;
413
414        // MapArray entries are stored as a StructArray with "keys" and "values" fields
415        let entries = array.entries();
416        let keys_array = entries
417            .column(0)
418            .as_any()
419            .downcast_ref::<<K as super::ArrowBindingView>::Array>()
420            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
421                expected: K::data_type(),
422                actual: entries.column(0).data_type().clone(),
423                field_name: Some("keys"),
424            })?;
425        let values_array = entries
426            .column(1)
427            .as_any()
428            .downcast_ref::<<V as super::ArrowBindingView>::Array>()
429            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
430                expected: V::data_type(),
431                actual: entries.column(1).data_type().clone(),
432                field_name: Some("values"),
433            })?;
434
435        Ok(MapView::new(keys_array, values_array, start, end))
436    }
437}
438
439#[cfg(feature = "views")]
440impl<K, V> super::ArrowBindingView for OrderedMap<K, V>
441where
442    K: ArrowBinding + Ord + super::ArrowBindingView + 'static,
443    V: ArrowBinding + super::ArrowBindingView + 'static,
444{
445    type Array = arrow_array::MapArray;
446    type View<'a> = MapView<'a, K, V, true>;
447
448    fn get_view(
449        array: &Self::Array,
450        index: usize,
451    ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
452        use arrow_array::Array;
453        if index >= array.len() {
454            return Err(crate::schema::ViewAccessError::OutOfBounds {
455                index,
456                len: array.len(),
457                field_name: None,
458            });
459        }
460        if array.is_null(index) {
461            return Err(crate::schema::ViewAccessError::UnexpectedNull {
462                index,
463                field_name: None,
464            });
465        }
466
467        let offsets = array.value_offsets();
468        let start = offsets[index] as usize;
469        let end = offsets[index + 1] as usize;
470
471        let entries = array.entries();
472        let keys_array = entries
473            .column(0)
474            .as_any()
475            .downcast_ref::<<K as super::ArrowBindingView>::Array>()
476            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
477                expected: K::data_type(),
478                actual: entries.column(0).data_type().clone(),
479                field_name: Some("keys"),
480            })?;
481        let values_array = entries
482            .column(1)
483            .as_any()
484            .downcast_ref::<<V as super::ArrowBindingView>::Array>()
485            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
486                expected: V::data_type(),
487                actual: entries.column(1).data_type().clone(),
488                field_name: Some("values"),
489            })?;
490
491        Ok(MapView::new(keys_array, values_array, start, end))
492    }
493}
494
495/// Iterator over views of map entries with nullable values.
496#[cfg(feature = "views")]
497pub struct MapViewNullable<'a, K, V, const SORTED: bool = false>
498where
499    K: super::ArrowBindingView + 'static,
500    V: super::ArrowBindingView + 'static,
501{
502    keys_array: &'a <K as super::ArrowBindingView>::Array,
503    values_array: &'a <V as super::ArrowBindingView>::Array,
504    start: usize,
505    end: usize,
506}
507
508#[cfg(feature = "views")]
509impl<'a, K, V, const SORTED: bool> MapViewNullable<'a, K, V, SORTED>
510where
511    K: super::ArrowBindingView + 'static,
512    V: super::ArrowBindingView + 'static,
513{
514    fn new(
515        keys_array: &'a <K as super::ArrowBindingView>::Array,
516        values_array: &'a <V as super::ArrowBindingView>::Array,
517        start: usize,
518        end: usize,
519    ) -> Self {
520        Self {
521            keys_array,
522            values_array,
523            start,
524            end,
525        }
526    }
527
528    /// Get the number of entries in the map.
529    #[inline]
530    pub fn len(&self) -> usize {
531        self.end - self.start
532    }
533
534    /// Check if the map is empty.
535    #[inline]
536    pub fn is_empty(&self) -> bool {
537        self.start == self.end
538    }
539}
540
541#[cfg(feature = "views")]
542impl<'a, K, V, EK, EV, const SORTED: bool> TryFrom<MapViewNullable<'a, K, V, SORTED>>
543    for Map<K, Option<V>, SORTED>
544where
545    K: super::ArrowBindingView + 'static,
546    V: super::ArrowBindingView + 'static,
547    K::View<'a>: TryInto<K, Error = EK>,
548    V::View<'a>: TryInto<V, Error = EV>,
549    EK: Into<crate::schema::ViewAccessError>,
550    EV: Into<crate::schema::ViewAccessError>,
551{
552    type Error = crate::schema::ViewAccessError;
553
554    fn try_from(view: MapViewNullable<'a, K, V, SORTED>) -> Result<Self, Self::Error> {
555        let mut entries = Vec::with_capacity(view.len());
556        for i in view.start..view.end {
557            use arrow_array::Array;
558            let key_view = K::get_view(view.keys_array, i)?;
559            let opt_value_view = if view.values_array.is_null(i) {
560                None
561            } else {
562                Some(V::get_view(view.values_array, i)?)
563            };
564            let opt_value_owned = match opt_value_view {
565                Some(v) => Some(v.try_into().map_err(|e| e.into())?),
566                None => None,
567            };
568            entries.push((key_view.try_into().map_err(|e| e.into())?, opt_value_owned));
569        }
570        Ok(Map::new(entries))
571    }
572}
573
574// TryFrom impls for OrderedMap (which uses MapView with SORTED=true)
575#[cfg(feature = "views")]
576impl<'a, K, V, EK, EV> TryFrom<MapView<'a, K, V, true>> for OrderedMap<K, V>
577where
578    K: super::ArrowBindingView + Ord + 'static,
579    V: super::ArrowBindingView + 'static,
580    K::View<'a>: TryInto<K, Error = EK>,
581    V::View<'a>: TryInto<V, Error = EV>,
582    EK: Into<crate::schema::ViewAccessError>,
583    EV: Into<crate::schema::ViewAccessError>,
584{
585    type Error = crate::schema::ViewAccessError;
586
587    fn try_from(view: MapView<'a, K, V, true>) -> Result<Self, Self::Error> {
588        let mut entries = std::collections::BTreeMap::new();
589        for i in view.start..view.end {
590            let key_view = K::get_view(view.keys_array, i)?;
591            let value_view = V::get_view(view.values_array, i)?;
592            entries.insert(
593                key_view.try_into().map_err(|e| e.into())?,
594                value_view.try_into().map_err(|e| e.into())?,
595            );
596        }
597        Ok(OrderedMap::new(entries))
598    }
599}
600
601#[cfg(feature = "views")]
602impl<'a, K, V, EK, EV> TryFrom<MapViewNullable<'a, K, V, true>> for OrderedMap<K, Option<V>>
603where
604    K: super::ArrowBindingView + Ord + 'static,
605    V: super::ArrowBindingView + 'static,
606    K::View<'a>: TryInto<K, Error = EK>,
607    V::View<'a>: TryInto<V, Error = EV>,
608    EK: Into<crate::schema::ViewAccessError>,
609    EV: Into<crate::schema::ViewAccessError>,
610{
611    type Error = crate::schema::ViewAccessError;
612
613    fn try_from(view: MapViewNullable<'a, K, V, true>) -> Result<Self, Self::Error> {
614        let mut entries = std::collections::BTreeMap::new();
615        for i in view.start..view.end {
616            use arrow_array::Array;
617            let key_view = K::get_view(view.keys_array, i)?;
618            let opt_value_view = if view.values_array.is_null(i) {
619                None
620            } else {
621                Some(V::get_view(view.values_array, i)?)
622            };
623            let opt_value_owned = match opt_value_view {
624                Some(v) => Some(v.try_into().map_err(|e| e.into())?),
625                None => None,
626            };
627            entries.insert(key_view.try_into().map_err(|e| e.into())?, opt_value_owned);
628        }
629        Ok(OrderedMap::new(entries))
630    }
631}
632
633#[cfg(feature = "views")]
634impl<'a, K, V, const SORTED: bool> Iterator for MapViewNullable<'a, K, V, SORTED>
635where
636    K: super::ArrowBindingView + 'static,
637    V: super::ArrowBindingView + 'static,
638{
639    type Item = Result<(K::View<'a>, Option<V::View<'a>>), crate::schema::ViewAccessError>;
640
641    fn next(&mut self) -> Option<Self::Item> {
642        if self.start < self.end {
643            let result = K::get_view(self.keys_array, self.start).and_then(|key| {
644                use arrow_array::Array;
645                let value = if self.values_array.is_null(self.start) {
646                    Ok(None)
647                } else {
648                    V::get_view(self.values_array, self.start).map(Some)
649                };
650                value.map(|v| (key, v))
651            });
652            self.start += 1;
653            Some(result)
654        } else {
655            None
656        }
657    }
658
659    fn size_hint(&self) -> (usize, Option<usize>) {
660        let remaining = self.end - self.start;
661        (remaining, Some(remaining))
662    }
663}
664
665#[cfg(feature = "views")]
666impl<'a, K, V, const SORTED: bool> ExactSizeIterator for MapViewNullable<'a, K, V, SORTED>
667where
668    K: super::ArrowBindingView + 'static,
669    V: super::ArrowBindingView + 'static,
670{
671    fn len(&self) -> usize {
672        self.end - self.start
673    }
674}
675
676#[cfg(feature = "views")]
677impl<K, V, const SORTED: bool> super::ArrowBindingView for Map<K, Option<V>, SORTED>
678where
679    K: ArrowBinding + super::ArrowBindingView + 'static,
680    V: ArrowBinding + super::ArrowBindingView + 'static,
681{
682    type Array = arrow_array::MapArray;
683    type View<'a> = MapViewNullable<'a, K, V, SORTED>;
684
685    fn get_view(
686        array: &Self::Array,
687        index: usize,
688    ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
689        use arrow_array::Array;
690        if index >= array.len() {
691            return Err(crate::schema::ViewAccessError::OutOfBounds {
692                index,
693                len: array.len(),
694                field_name: None,
695            });
696        }
697        if array.is_null(index) {
698            return Err(crate::schema::ViewAccessError::UnexpectedNull {
699                index,
700                field_name: None,
701            });
702        }
703
704        let offsets = array.value_offsets();
705        let start = offsets[index] as usize;
706        let end = offsets[index + 1] as usize;
707
708        let entries = array.entries();
709        let keys_array = entries
710            .column(0)
711            .as_any()
712            .downcast_ref::<<K as super::ArrowBindingView>::Array>()
713            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
714                expected: K::data_type(),
715                actual: entries.column(0).data_type().clone(),
716                field_name: Some("keys"),
717            })?;
718        let values_array = entries
719            .column(1)
720            .as_any()
721            .downcast_ref::<<V as super::ArrowBindingView>::Array>()
722            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
723                expected: V::data_type(),
724                actual: entries.column(1).data_type().clone(),
725                field_name: Some("values"),
726            })?;
727
728        Ok(MapViewNullable::new(keys_array, values_array, start, end))
729    }
730}
731
732#[cfg(feature = "views")]
733impl<K, V> super::ArrowBindingView for OrderedMap<K, Option<V>>
734where
735    K: ArrowBinding + Ord + super::ArrowBindingView + 'static,
736    V: ArrowBinding + super::ArrowBindingView + 'static,
737{
738    type Array = arrow_array::MapArray;
739    type View<'a> = MapViewNullable<'a, K, V, true>;
740
741    fn get_view(
742        array: &Self::Array,
743        index: usize,
744    ) -> Result<Self::View<'_>, crate::schema::ViewAccessError> {
745        use arrow_array::Array;
746        if index >= array.len() {
747            return Err(crate::schema::ViewAccessError::OutOfBounds {
748                index,
749                len: array.len(),
750                field_name: None,
751            });
752        }
753        if array.is_null(index) {
754            return Err(crate::schema::ViewAccessError::UnexpectedNull {
755                index,
756                field_name: None,
757            });
758        }
759
760        let offsets = array.value_offsets();
761        let start = offsets[index] as usize;
762        let end = offsets[index + 1] as usize;
763
764        let entries = array.entries();
765        let keys_array = entries
766            .column(0)
767            .as_any()
768            .downcast_ref::<<K as super::ArrowBindingView>::Array>()
769            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
770                expected: K::data_type(),
771                actual: entries.column(0).data_type().clone(),
772                field_name: Some("keys"),
773            })?;
774        let values_array = entries
775            .column(1)
776            .as_any()
777            .downcast_ref::<<V as super::ArrowBindingView>::Array>()
778            .ok_or_else(|| crate::schema::ViewAccessError::TypeMismatch {
779                expected: V::data_type(),
780                actual: entries.column(1).data_type().clone(),
781                field_name: Some("values"),
782            })?;
783
784        Ok(MapViewNullable::new(keys_array, values_array, start, end))
785    }
786}