typed_arrow/bridge/
map.rs

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