Skip to main content

arrow_schema/
fields.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::ops::Deref;
19use std::sync::Arc;
20
21use crate::{ArrowError, DataType, Field, FieldRef};
22
23/// A cheaply cloneable, owned slice of [`FieldRef`]
24///
25/// Similar to `Arc<Vec<FieldRef>>` or `Arc<[FieldRef]>`
26///
27/// Can be constructed in a number of ways
28///
29/// ```
30/// # use std::sync::Arc;
31/// # use arrow_schema::{DataType, Field, Fields, SchemaBuilder};
32/// // Can be constructed from Vec<Field>
33/// Fields::from(vec![Field::new("a", DataType::Boolean, false)]);
34/// // Can be constructed from Vec<FieldRef>
35/// Fields::from(vec![Arc::new(Field::new("a", DataType::Boolean, false))]);
36/// // Can be constructed from an iterator of Field
37/// std::iter::once(Field::new("a", DataType::Boolean, false)).collect::<Fields>();
38/// // Can be constructed from an iterator of FieldRef
39/// std::iter::once(Arc::new(Field::new("a", DataType::Boolean, false))).collect::<Fields>();
40/// ```
41///
42/// See [`SchemaBuilder`] for mutating or updating [`Fields`]
43///
44/// ```
45/// # use arrow_schema::{DataType, Field, SchemaBuilder};
46/// let mut builder = SchemaBuilder::new();
47/// builder.push(Field::new("a", DataType::Boolean, false));
48/// builder.push(Field::new("b", DataType::Boolean, false));
49/// let fields = builder.finish().fields;
50///
51/// let mut builder = SchemaBuilder::from(&fields);
52/// builder.remove(0);
53/// let new = builder.finish().fields;
54/// ```
55///
56/// [`SchemaBuilder`]: crate::SchemaBuilder
57#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
58#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
59#[cfg_attr(feature = "serde", serde(transparent))]
60pub struct Fields(Arc<[FieldRef]>);
61
62impl std::fmt::Debug for Fields {
63    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64        self.0.as_ref().fmt(f)
65    }
66}
67
68impl Fields {
69    /// Returns a new empty [`Fields`]
70    pub fn empty() -> Self {
71        Self(Arc::new([]))
72    }
73
74    /// Return size of this instance in bytes.
75    pub fn size(&self) -> usize {
76        self.iter()
77            .map(|field| field.size() + std::mem::size_of::<FieldRef>())
78            .sum()
79    }
80
81    /// Searches for a field by name, returning it along with its index if found
82    pub fn find(&self, name: &str) -> Option<(usize, &FieldRef)> {
83        self.0.iter().enumerate().find(|(_, b)| b.name() == name)
84    }
85
86    /// Check to see if `self` is a superset of `other`
87    ///
88    /// In particular returns true if both have the same number of fields, and [`Field::contains`]
89    /// for each field across self and other
90    ///
91    /// In other words, any record that conforms to `other` should also conform to `self`
92    pub fn contains(&self, other: &Fields) -> bool {
93        if Arc::ptr_eq(&self.0, &other.0) {
94            return true;
95        }
96        self.len() == other.len()
97            && self
98                .iter()
99                .zip(other.iter())
100                .all(|(a, b)| Arc::ptr_eq(a, b) || a.contains(b))
101    }
102
103    /// Returns a copy of this [`Fields`] containing only those [`FieldRef`] passing a predicate
104    ///
105    /// Performs a depth-first scan of [`Fields`] invoking `filter` for each [`FieldRef`]
106    /// containing no child [`FieldRef`], a leaf field, along with a count of the number
107    /// of such leaves encountered so far. Only [`FieldRef`] for which `filter`
108    /// returned `true` will be included in the result.
109    ///
110    /// This can therefore be used to select a subset of fields from nested types
111    /// such as [`DataType::Struct`] or [`DataType::List`].
112    ///
113    /// ```
114    /// # use arrow_schema::{DataType, Field, Fields};
115    /// let fields = Fields::from(vec![
116    ///     Field::new("a", DataType::Int32, true), // Leaf 0
117    ///     Field::new("b", DataType::Struct(Fields::from(vec![
118    ///         Field::new("c", DataType::Float32, false), // Leaf 1
119    ///         Field::new("d", DataType::Float64, false), // Leaf 2
120    ///         Field::new("e", DataType::Struct(Fields::from(vec![
121    ///             Field::new("f", DataType::Int32, false),   // Leaf 3
122    ///             Field::new("g", DataType::Float16, false), // Leaf 4
123    ///         ])), true),
124    ///     ])), false)
125    /// ]);
126    /// let filtered = fields.filter_leaves(|idx, _| [0, 2, 3, 4].contains(&idx));
127    /// let expected = Fields::from(vec![
128    ///     Field::new("a", DataType::Int32, true),
129    ///     Field::new("b", DataType::Struct(Fields::from(vec![
130    ///         Field::new("d", DataType::Float64, false),
131    ///         Field::new("e", DataType::Struct(Fields::from(vec![
132    ///             Field::new("f", DataType::Int32, false),
133    ///             Field::new("g", DataType::Float16, false),
134    ///         ])), true),
135    ///     ])), false)
136    /// ]);
137    /// assert_eq!(filtered, expected);
138    /// ```
139    pub fn filter_leaves<F: FnMut(usize, &FieldRef) -> bool>(&self, mut filter: F) -> Self {
140        self.try_filter_leaves(|idx, field| Ok(filter(idx, field)))
141            .unwrap()
142    }
143
144    /// Returns a copy of this [`Fields`] containing only those [`FieldRef`] passing a predicate
145    /// or an error if the predicate fails.
146    ///
147    /// See [`Fields::filter_leaves`] for more information.
148    pub fn try_filter_leaves<F: FnMut(usize, &FieldRef) -> Result<bool, ArrowError>>(
149        &self,
150        mut filter: F,
151    ) -> Result<Self, ArrowError> {
152        fn filter_field<F: FnMut(&FieldRef) -> Result<bool, ArrowError>>(
153            f: &FieldRef,
154            filter: &mut F,
155        ) -> Result<Option<FieldRef>, ArrowError> {
156            use DataType::*;
157
158            let v = match f.data_type() {
159                Dictionary(_, v) => v.as_ref(),       // Key must be integer
160                RunEndEncoded(_, v) => v.data_type(), // Run-ends must be integer
161                d => d,
162            };
163            let d = match v {
164                List(child) => {
165                    let fields = filter_field(child, filter)?;
166                    if let Some(fields) = fields {
167                        List(fields)
168                    } else {
169                        return Ok(None);
170                    }
171                }
172                LargeList(child) => {
173                    let fields = filter_field(child, filter)?;
174                    if let Some(fields) = fields {
175                        LargeList(fields)
176                    } else {
177                        return Ok(None);
178                    }
179                }
180                Map(child, ordered) => {
181                    let fields = filter_field(child, filter)?;
182                    if let Some(fields) = fields {
183                        Map(fields, *ordered)
184                    } else {
185                        return Ok(None);
186                    }
187                }
188                FixedSizeList(child, size) => {
189                    let fields = filter_field(child, filter)?;
190                    if let Some(fields) = fields {
191                        FixedSizeList(fields, *size)
192                    } else {
193                        return Ok(None);
194                    }
195                }
196                Struct(fields) => {
197                    let filtered: Result<Vec<_>, _> =
198                        fields.iter().map(|f| filter_field(f, filter)).collect();
199                    let filtered: Fields = filtered?
200                        .iter()
201                        .filter_map(|f| f.as_ref().cloned())
202                        .collect();
203
204                    if filtered.is_empty() {
205                        return Ok(None);
206                    }
207
208                    Struct(filtered)
209                }
210                Union(fields, mode) => {
211                    let filtered: Result<Vec<_>, _> = fields
212                        .iter()
213                        .map(|(id, f)| filter_field(f, filter).map(|f| f.map(|f| (id, f))))
214                        .collect();
215                    let filtered: UnionFields = filtered?
216                        .iter()
217                        .filter_map(|f| f.as_ref().cloned())
218                        .collect();
219
220                    if filtered.is_empty() {
221                        return Ok(None);
222                    }
223
224                    Union(filtered, *mode)
225                }
226                _ => {
227                    let filtered = filter(f)?;
228                    return Ok(filtered.then(|| f.clone()));
229                }
230            };
231            let d = match f.data_type() {
232                Dictionary(k, _) => Dictionary(k.clone(), Box::new(d)),
233                RunEndEncoded(v, f) => {
234                    RunEndEncoded(v.clone(), Arc::new(f.as_ref().clone().with_data_type(d)))
235                }
236                _ => d,
237            };
238            Ok(Some(Arc::new(f.as_ref().clone().with_data_type(d))))
239        }
240
241        let mut leaf_idx = 0;
242        let mut filter = |f: &FieldRef| {
243            let t = filter(leaf_idx, f)?;
244            leaf_idx += 1;
245            Ok(t)
246        };
247
248        let filtered: Result<Vec<_>, _> = self
249            .0
250            .iter()
251            .map(|f| filter_field(f, &mut filter))
252            .collect();
253        let filtered = filtered?
254            .iter()
255            .filter_map(|f| f.as_ref().cloned())
256            .collect();
257        Ok(filtered)
258    }
259}
260
261impl Default for Fields {
262    fn default() -> Self {
263        Self::empty()
264    }
265}
266
267impl FromIterator<Field> for Fields {
268    fn from_iter<T: IntoIterator<Item = Field>>(iter: T) -> Self {
269        iter.into_iter().map(Arc::new).collect()
270    }
271}
272
273impl FromIterator<FieldRef> for Fields {
274    fn from_iter<T: IntoIterator<Item = FieldRef>>(iter: T) -> Self {
275        Self(iter.into_iter().collect())
276    }
277}
278
279impl From<Vec<Field>> for Fields {
280    fn from(value: Vec<Field>) -> Self {
281        value.into_iter().collect()
282    }
283}
284
285impl From<Vec<FieldRef>> for Fields {
286    fn from(value: Vec<FieldRef>) -> Self {
287        Self(value.into())
288    }
289}
290
291impl From<&[FieldRef]> for Fields {
292    fn from(value: &[FieldRef]) -> Self {
293        Self(value.into())
294    }
295}
296
297impl<const N: usize> From<[FieldRef; N]> for Fields {
298    fn from(value: [FieldRef; N]) -> Self {
299        Self(Arc::new(value))
300    }
301}
302
303impl Deref for Fields {
304    type Target = [FieldRef];
305
306    fn deref(&self) -> &Self::Target {
307        self.0.as_ref()
308    }
309}
310
311impl<'a> IntoIterator for &'a Fields {
312    type Item = &'a FieldRef;
313    type IntoIter = std::slice::Iter<'a, FieldRef>;
314
315    fn into_iter(self) -> Self::IntoIter {
316        self.0.iter()
317    }
318}
319
320/// A cheaply cloneable, owned collection of [`FieldRef`] and their corresponding
321/// type ids.
322///
323/// Invariants:
324/// - All type ids are unique
325/// - All type ids are non-negative
326#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
327#[cfg_attr(feature = "serde", derive(serde::Serialize))]
328#[cfg_attr(feature = "serde", serde(transparent))]
329pub struct UnionFields(Arc<[(i8, FieldRef)]>);
330
331// Manual implementation to enforce invariants per docstring above
332#[cfg(feature = "serde")]
333impl<'de> serde::Deserialize<'de> for UnionFields {
334    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
335    where
336        D: serde::Deserializer<'de>,
337    {
338        let entries = Vec::<(i8, FieldRef)>::deserialize(deserializer)?;
339        let (type_ids, fields): (Vec<i8>, Vec<FieldRef>) = entries.into_iter().unzip();
340        Self::try_new(type_ids, fields).map_err(serde::de::Error::custom)
341    }
342}
343
344impl std::fmt::Debug for UnionFields {
345    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
346        self.0.as_ref().fmt(f)
347    }
348}
349
350/// Allows direct indexing into [`UnionFields`] to access fields by position.
351///
352/// # Panics
353///
354/// Panics if the index is out of bounds. Note that [`UnionFields`] supports
355/// a maximum of 128 fields, as type IDs are represented as `i8` values.
356///
357/// For a non-panicking alternative, use [`UnionFields::get`].
358impl std::ops::Index<usize> for UnionFields {
359    type Output = (i8, FieldRef);
360
361    fn index(&self, index: usize) -> &Self::Output {
362        &self.0[index]
363    }
364}
365
366impl UnionFields {
367    /// Create a new [`UnionFields`] with no fields
368    pub fn empty() -> Self {
369        Self(Arc::from([]))
370    }
371
372    /// Create a new [`UnionFields`] from a [`Fields`] and array of type_ids
373    ///
374    /// See <https://arrow.apache.org/docs/format/Columnar.html#union-layout>
375    ///
376    /// # Errors
377    ///
378    /// This function returns an error if:
379    /// - Iterators are not the same length
380    /// - Any type_id appears more than once (duplicate type ids)
381    /// - There is a negative type_id
382    ///
383    /// # Examples
384    ///
385    /// ```
386    /// use arrow_schema::{DataType, Field, UnionFields};
387    /// // Create a new UnionFields with type id mapping
388    /// // 1 -> DataType::UInt8
389    /// // 3 -> DataType::Utf8
390    /// let result = UnionFields::try_new(
391    ///     vec![1, 3],
392    ///     vec![
393    ///         Field::new("field1", DataType::UInt8, false),
394    ///         Field::new("field3", DataType::Utf8, false),
395    ///     ],
396    /// );
397    /// assert!(result.is_ok());
398    ///
399    /// // This will fail due to duplicate type ids
400    /// let result = UnionFields::try_new(
401    ///     vec![1, 1],
402    ///     vec![
403    ///         Field::new("field1", DataType::UInt8, false),
404    ///         Field::new("field2", DataType::Utf8, false),
405    ///     ],
406    /// );
407    /// assert!(result.is_err());
408    /// ```
409    pub fn try_new<F, T>(type_ids: T, fields: F) -> Result<Self, ArrowError>
410    where
411        F: IntoIterator,
412        F::Item: Into<FieldRef>,
413        T: IntoIterator<Item = i8>,
414    {
415        let mut type_ids_iter = type_ids.into_iter();
416        let mut fields_iter = fields.into_iter().map(Into::into);
417
418        let mut seen_type_ids = 0u128;
419
420        let mut out = Vec::new();
421
422        loop {
423            match (type_ids_iter.next(), fields_iter.next()) {
424                (None, None) => return Ok(Self(out.into())),
425                (Some(type_id), Some(field)) => {
426                    // check type id is non-negative
427                    if type_id < 0 {
428                        return Err(ArrowError::InvalidArgumentError(format!(
429                            "type ids must be non-negative: {type_id}"
430                        )));
431                    }
432
433                    // check type id uniqueness
434                    let mask = 1_u128 << type_id;
435                    if (seen_type_ids & mask) != 0 {
436                        return Err(ArrowError::InvalidArgumentError(format!(
437                            "duplicate type id: {type_id}"
438                        )));
439                    }
440
441                    seen_type_ids |= mask;
442
443                    out.push((type_id, field));
444                }
445                (None, Some(_)) => {
446                    return Err(ArrowError::InvalidArgumentError(
447                        "fields iterator has more elements than type_ids iterator".to_string(),
448                    ));
449                }
450                (Some(_), None) => {
451                    return Err(ArrowError::InvalidArgumentError(
452                        "type_ids iterator has more elements than fields iterator".to_string(),
453                    ));
454                }
455            }
456        }
457    }
458
459    /// Create a new [`UnionFields`] from a collection of fields with automatically
460    /// assigned type IDs starting from 0.
461    ///
462    /// The type IDs are assigned in increasing order: 0, 1, 2, 3, etc.
463    ///
464    /// See <https://arrow.apache.org/docs/format/Columnar.html#union-layout>
465    ///
466    /// # Panics
467    ///
468    /// Panics if the number of fields exceeds 127 (the maximum value for i8 type IDs).
469    ///
470    /// If you want to avoid panics, use [`UnionFields::try_from_fields`] instead, which
471    /// returns a `Result`.
472    ///
473    /// # Examples
474    ///
475    /// ```
476    /// use arrow_schema::{DataType, Field, UnionFields};
477    /// // Create a new UnionFields with automatic type id assignment
478    /// // 0 -> DataType::UInt8
479    /// // 1 -> DataType::Utf8
480    /// let union_fields = UnionFields::from_fields(vec![
481    ///     Field::new("field1", DataType::UInt8, false),
482    ///     Field::new("field2", DataType::Utf8, false),
483    /// ]);
484    /// assert_eq!(union_fields.len(), 2);
485    /// ```
486    pub fn from_fields<F>(fields: F) -> Self
487    where
488        F: IntoIterator,
489        F::Item: Into<FieldRef>,
490    {
491        fields
492            .into_iter()
493            .enumerate()
494            .map(|(i, field)| {
495                let id = i8::try_from(i).expect("UnionFields cannot contain more than 128 fields");
496
497                (id, field.into())
498            })
499            .collect()
500    }
501
502    /// Create a new [`UnionFields`] from a collection of fields with automatically
503    /// assigned type IDs starting from 0.
504    ///
505    /// The type IDs are assigned in increasing order: 0, 1, 2, 3, etc.
506    ///
507    /// This is the non-panicking version of [`UnionFields::from_fields`].
508    ///
509    /// See <https://arrow.apache.org/docs/format/Columnar.html#union-layout>
510    ///
511    /// # Errors
512    ///
513    /// Returns an error if the number of fields exceeds 127 (the maximum value for i8 type IDs).
514    ///
515    /// # Examples
516    ///
517    /// ```
518    /// use arrow_schema::{DataType, Field, UnionFields};
519    /// // Create a new UnionFields with automatic type id assignment
520    /// // 0 -> DataType::UInt8
521    /// // 1 -> DataType::Utf8
522    /// let result = UnionFields::try_from_fields(vec![
523    ///     Field::new("field1", DataType::UInt8, false),
524    ///     Field::new("field2", DataType::Utf8, false),
525    /// ]);
526    /// assert!(result.is_ok());
527    /// assert_eq!(result.unwrap().len(), 2);
528    ///
529    /// // This will fail with too many fields
530    /// let many_fields: Vec<_> = (0..200)
531    ///     .map(|i| Field::new(format!("field{}", i), DataType::Int32, false))
532    ///     .collect();
533    /// let result = UnionFields::try_from_fields(many_fields);
534    /// assert!(result.is_err());
535    /// ```
536    pub fn try_from_fields<F>(fields: F) -> Result<Self, ArrowError>
537    where
538        F: IntoIterator,
539        F::Item: Into<FieldRef>,
540    {
541        let mut out = Vec::with_capacity(i8::MAX as usize + 1);
542
543        for (i, field) in fields.into_iter().enumerate() {
544            let id = i8::try_from(i).map_err(|_| {
545                ArrowError::InvalidArgumentError(
546                    "UnionFields cannot contain more than 128 fields".into(),
547                )
548            })?;
549
550            out.push((id, field.into()));
551        }
552
553        Ok(Self(out.into()))
554    }
555
556    /// Create a new [`UnionFields`] from a [`Fields`] and array of type_ids
557    ///
558    /// See <https://arrow.apache.org/docs/format/Columnar.html#union-layout>
559    ///
560    /// # Deprecated
561    ///
562    /// Use [`UnionFields::try_new`] instead. This method panics on invalid input,
563    /// while `try_new` returns a `Result`.
564    ///
565    /// # Panics
566    ///
567    /// Panics if any type_id appears more than once (duplicate type ids).
568    ///
569    /// ```
570    /// use arrow_schema::{DataType, Field, UnionFields};
571    /// // Create a new UnionFields with type id mapping
572    /// // 1 -> DataType::UInt8
573    /// // 3 -> DataType::Utf8
574    /// UnionFields::try_new(
575    ///     vec![1, 3],
576    ///     vec![
577    ///         Field::new("field1", DataType::UInt8, false),
578    ///         Field::new("field3", DataType::Utf8, false),
579    ///     ],
580    /// );
581    /// ```
582    #[deprecated(since = "57.0.0", note = "Use `try_new` instead")]
583    pub fn new<F, T>(type_ids: T, fields: F) -> Self
584    where
585        F: IntoIterator,
586        F::Item: Into<FieldRef>,
587        T: IntoIterator<Item = i8>,
588    {
589        let fields = fields.into_iter().map(Into::into);
590        let mut set = 0_u128;
591        type_ids
592            .into_iter()
593            .inspect(|&idx| {
594                let mask = 1_u128 << idx;
595                if (set & mask) != 0 {
596                    panic!("duplicate type id: {idx}");
597                } else {
598                    set |= mask;
599                }
600            })
601            .zip(fields)
602            .collect()
603    }
604
605    /// Return size of this instance in bytes.
606    pub fn size(&self) -> usize {
607        self.iter()
608            .map(|(_, field)| field.size() + std::mem::size_of::<(i8, FieldRef)>())
609            .sum()
610    }
611
612    /// Returns the number of fields in this [`UnionFields`]
613    pub fn len(&self) -> usize {
614        self.0.len()
615    }
616
617    /// Returns `true` if this is empty
618    pub fn is_empty(&self) -> bool {
619        self.0.is_empty()
620    }
621
622    /// Returns an iterator over the fields and type ids in this [`UnionFields`]
623    pub fn iter(&self) -> impl Iterator<Item = (i8, &FieldRef)> + '_ {
624        self.0.iter().map(|(id, f)| (*id, f))
625    }
626
627    /// Returns a reference to the field at the given index, or `None` if out of bounds.
628    ///
629    /// This is a safe alternative to direct indexing via `[]`.
630    ///
631    /// # Example
632    ///
633    /// ```
634    /// use arrow_schema::{DataType, Field, UnionFields};
635    ///
636    /// let fields = UnionFields::new(
637    ///     vec![1, 3],
638    ///     vec![
639    ///         Field::new("field1", DataType::UInt8, false),
640    ///         Field::new("field3", DataType::Utf8, false),
641    ///     ],
642    /// );
643    ///
644    /// assert!(fields.get(0).is_some());
645    /// assert!(fields.get(1).is_some());
646    /// assert!(fields.get(2).is_none());
647    /// ```
648    pub fn get(&self, index: usize) -> Option<&(i8, FieldRef)> {
649        self.0.get(index)
650    }
651
652    /// Searches for a field by its type id, returning the type id and field reference if found.
653    /// Returns `None` if no field with the given type id exists.
654    pub fn find_by_type_id(&self, type_id: i8) -> Option<(i8, &FieldRef)> {
655        self.iter().find(|&(i, _)| i == type_id)
656    }
657
658    /// Searches for a field by value equality, returning its type id and reference if found.
659    /// Returns `None` if no matching field exists in this [`UnionFields`].
660    pub fn find_by_field(&self, field: &Field) -> Option<(i8, &FieldRef)> {
661        self.iter().find(|&(_, f)| f.as_ref() == field)
662    }
663
664    /// Merge this field into self if it is compatible.
665    ///
666    /// See [`Field::try_merge`]
667    pub(crate) fn try_merge(&mut self, other: &Self) -> Result<(), ArrowError> {
668        // TODO: This currently may produce duplicate type IDs (#3982)
669        let mut output: Vec<_> = self.iter().map(|(id, f)| (id, f.clone())).collect();
670        for (field_type_id, from_field) in other.iter() {
671            let mut is_new_field = true;
672            for (self_type_id, self_field) in output.iter_mut() {
673                if from_field == self_field {
674                    // If the nested fields in two unions are the same, they must have same
675                    // type id.
676                    if *self_type_id != field_type_id {
677                        return Err(ArrowError::SchemaError(format!(
678                            "Fail to merge schema field '{}' because the self_type_id = {} does not equal field_type_id = {}",
679                            self_field.name(),
680                            self_type_id,
681                            field_type_id
682                        )));
683                    }
684
685                    is_new_field = false;
686                    break;
687                }
688            }
689
690            if is_new_field {
691                output.push((field_type_id, from_field.clone()))
692            }
693        }
694        // TODO: see above comment; can we remove the need to go through try_new
695        //       and just validate in this function ourselves?
696        let (type_ids, fields): (Vec<i8>, Vec<FieldRef>) = output.into_iter().unzip();
697        *self = Self::try_new(type_ids, fields)?;
698        Ok(())
699    }
700}
701
702impl FromIterator<(i8, FieldRef)> for UnionFields {
703    /// # Panics
704    ///
705    /// This will panic on invalid inputs:
706    /// - Duplicate type IDs
707    /// - Negative type IDs
708    ///
709    /// Prefer using [`UnionFields::try_new`] for a fallible construction method.
710    fn from_iter<T: IntoIterator<Item = (i8, FieldRef)>>(iter: T) -> Self {
711        let iter = iter.into_iter();
712        let (type_ids, fields): (Vec<i8>, Vec<FieldRef>) = iter.unzip();
713        Self::try_new(type_ids, fields).expect("invalid arguments passed")
714    }
715}
716
717#[cfg(test)]
718mod tests {
719    use super::*;
720    use crate::UnionMode;
721
722    #[test]
723    fn test_filter() {
724        let floats = Fields::from(vec![
725            Field::new("a", DataType::Float32, false),
726            Field::new("b", DataType::Float32, false),
727        ]);
728        let fields = Fields::from(vec![
729            Field::new("a", DataType::Int32, true),
730            Field::new("floats", DataType::Struct(floats.clone()), true),
731            Field::new("b", DataType::Int16, true),
732            Field::new(
733                "c",
734                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
735                false,
736            ),
737            Field::new(
738                "d",
739                DataType::Dictionary(
740                    Box::new(DataType::Int32),
741                    Box::new(DataType::Struct(floats.clone())),
742                ),
743                false,
744            ),
745            Field::new_list(
746                "e",
747                Field::new("floats", DataType::Struct(floats.clone()), true),
748                true,
749            ),
750            Field::new_fixed_size_list(
751                "f",
752                Field::new_list_field(DataType::Int32, false),
753                3,
754                false,
755            ),
756            Field::new_map(
757                "g",
758                "entries",
759                Field::new("keys", DataType::LargeUtf8, false),
760                Field::new("values", DataType::Int32, true),
761                false,
762                false,
763            ),
764            Field::new(
765                "h",
766                DataType::Union(
767                    UnionFields::try_new(
768                        vec![1, 3],
769                        vec![
770                            Field::new("field1", DataType::UInt8, false),
771                            Field::new("field3", DataType::Utf8, false),
772                        ],
773                    )
774                    .unwrap(),
775                    UnionMode::Dense,
776                ),
777                true,
778            ),
779            Field::new(
780                "i",
781                DataType::RunEndEncoded(
782                    Arc::new(Field::new("run_ends", DataType::Int32, false)),
783                    Arc::new(Field::new("values", DataType::Struct(floats.clone()), true)),
784                ),
785                false,
786            ),
787        ]);
788
789        let floats_a = DataType::Struct(vec![floats[0].clone()].into());
790
791        let r = fields.filter_leaves(|idx, _| idx == 0 || idx == 1);
792        assert_eq!(r.len(), 2);
793        assert_eq!(r[0], fields[0]);
794        assert_eq!(r[1].data_type(), &floats_a);
795
796        let r = fields.filter_leaves(|_, f| f.name() == "a");
797        assert_eq!(r.len(), 5);
798        assert_eq!(r[0], fields[0]);
799        assert_eq!(r[1].data_type(), &floats_a);
800        assert_eq!(
801            r[2].data_type(),
802            &DataType::Dictionary(Box::new(DataType::Int32), Box::new(floats_a.clone()))
803        );
804        assert_eq!(
805            r[3].as_ref(),
806            &Field::new_list("e", Field::new("floats", floats_a.clone(), true), true)
807        );
808        assert_eq!(
809            r[4].as_ref(),
810            &Field::new(
811                "i",
812                DataType::RunEndEncoded(
813                    Arc::new(Field::new("run_ends", DataType::Int32, false)),
814                    Arc::new(Field::new("values", floats_a.clone(), true)),
815                ),
816                false,
817            )
818        );
819
820        let r = fields.filter_leaves(|_, f| f.name() == "floats");
821        assert_eq!(r.len(), 0);
822
823        let r = fields.filter_leaves(|idx, _| idx == 9);
824        assert_eq!(r.len(), 1);
825        assert_eq!(r[0], fields[6]);
826
827        let r = fields.filter_leaves(|idx, _| idx == 10 || idx == 11);
828        assert_eq!(r.len(), 1);
829        assert_eq!(r[0], fields[7]);
830
831        let union = DataType::Union(
832            UnionFields::try_new(vec![1], vec![Field::new("field1", DataType::UInt8, false)])
833                .unwrap(),
834            UnionMode::Dense,
835        );
836
837        let r = fields.filter_leaves(|idx, _| idx == 12);
838        assert_eq!(r.len(), 1);
839        assert_eq!(r[0].data_type(), &union);
840
841        let r = fields.filter_leaves(|idx, _| idx == 14 || idx == 15);
842        assert_eq!(r.len(), 1);
843        assert_eq!(r[0], fields[9]);
844
845        // Propagate error
846        let r = fields.try_filter_leaves(|_, _| Err(ArrowError::SchemaError("error".to_string())));
847        assert!(r.is_err());
848    }
849
850    #[test]
851    fn test_union_fields_try_new_valid() {
852        let res = UnionFields::try_new(
853            vec![1, 6, 7],
854            vec![
855                Field::new("f1", DataType::UInt8, false),
856                Field::new("f6", DataType::Utf8, false),
857                Field::new("f7", DataType::Int32, true),
858            ],
859        );
860        assert!(res.is_ok());
861        let union_fields = res.unwrap();
862        assert_eq!(union_fields.len(), 3);
863        assert_eq!(
864            union_fields.iter().map(|(id, _)| id).collect::<Vec<_>>(),
865            vec![1, 6, 7]
866        );
867    }
868
869    #[test]
870    fn test_union_fields_try_new_empty() {
871        let res = UnionFields::try_new(Vec::<i8>::new(), Vec::<Field>::new());
872        assert!(res.is_ok());
873        assert!(res.unwrap().is_empty());
874    }
875
876    #[test]
877    fn test_union_fields_try_new_duplicate_type_id() {
878        let res = UnionFields::try_new(
879            vec![1, 1],
880            vec![
881                Field::new("f1", DataType::UInt8, false),
882                Field::new("f2", DataType::Utf8, false),
883            ],
884        );
885        assert!(res.is_err());
886        assert!(
887            res.unwrap_err()
888                .to_string()
889                .contains("duplicate type id: 1")
890        );
891    }
892
893    #[test]
894    fn test_union_fields_try_new_duplicate_field() {
895        let field = Field::new("field", DataType::UInt8, false);
896        let res = UnionFields::try_new(vec![1, 2], vec![field.clone(), field]);
897        assert!(res.is_ok());
898    }
899
900    #[test]
901    fn test_union_fields_try_new_more_type_ids() {
902        let res = UnionFields::try_new(
903            vec![1, 2, 3],
904            vec![
905                Field::new("f1", DataType::UInt8, false),
906                Field::new("f2", DataType::Utf8, false),
907            ],
908        );
909        assert!(res.is_err());
910        assert!(
911            res.unwrap_err()
912                .to_string()
913                .contains("type_ids iterator has more elements")
914        );
915    }
916
917    #[test]
918    fn test_union_fields_try_new_more_fields() {
919        let res = UnionFields::try_new(
920            vec![1, 2],
921            vec![
922                Field::new("f1", DataType::UInt8, false),
923                Field::new("f2", DataType::Utf8, false),
924                Field::new("f3", DataType::Int32, true),
925            ],
926        );
927        assert!(res.is_err());
928        assert!(
929            res.unwrap_err()
930                .to_string()
931                .contains("fields iterator has more elements")
932        );
933    }
934
935    #[test]
936    fn test_union_fields_try_new_negative_type_ids() {
937        let res = UnionFields::try_new(
938            vec![-128, -1, 0, 127],
939            vec![
940                Field::new("field_min", DataType::UInt8, false),
941                Field::new("field_neg", DataType::Utf8, false),
942                Field::new("field_zero", DataType::Int32, true),
943                Field::new("field_max", DataType::Boolean, false),
944            ],
945        );
946        assert!(res.is_err());
947        assert!(
948            res.unwrap_err()
949                .to_string()
950                .contains("type ids must be non-negative")
951        )
952    }
953
954    #[test]
955    fn test_union_fields_try_new_complex_types() {
956        let res = UnionFields::try_new(
957            vec![0, 1, 2],
958            vec![
959                Field::new(
960                    "struct_field",
961                    DataType::Struct(Fields::from(vec![
962                        Field::new("a", DataType::Int32, false),
963                        Field::new("b", DataType::Utf8, true),
964                    ])),
965                    false,
966                ),
967                Field::new_list(
968                    "list_field",
969                    Field::new("item", DataType::Float64, true),
970                    true,
971                ),
972                Field::new(
973                    "dict_field",
974                    DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
975                    false,
976                ),
977            ],
978        );
979        assert!(res.is_ok());
980        assert_eq!(res.unwrap().len(), 3);
981    }
982
983    #[test]
984    fn test_union_fields_try_new_single_field() {
985        let res = UnionFields::try_new(
986            vec![42],
987            vec![Field::new("only_field", DataType::Int64, false)],
988        );
989        assert!(res.is_ok());
990        let union_fields = res.unwrap();
991        assert_eq!(union_fields.len(), 1);
992        assert_eq!(union_fields.iter().next().unwrap().0, 42);
993    }
994
995    #[test]
996    fn test_union_fields_try_from_fields_empty() {
997        let res = UnionFields::try_from_fields(Vec::<Field>::new());
998        assert!(res.is_ok());
999        assert!(res.unwrap().is_empty());
1000    }
1001
1002    #[test]
1003    fn test_union_fields_try_from_fields_single() {
1004        let res = UnionFields::try_from_fields(vec![Field::new("only", DataType::Int64, false)]);
1005        assert!(res.is_ok());
1006        let union_fields = res.unwrap();
1007        assert_eq!(union_fields.len(), 1);
1008        assert_eq!(union_fields.iter().next().unwrap().0, 0);
1009    }
1010
1011    #[test]
1012    fn test_union_fields_try_from_fields_too_many() {
1013        let many_fields: Vec<_> = (0..200)
1014            .map(|i| Field::new(format!("field{}", i), DataType::Int32, false))
1015            .collect();
1016        let res = UnionFields::try_from_fields(many_fields);
1017        assert!(res.is_err());
1018        assert!(
1019            res.unwrap_err()
1020                .to_string()
1021                .contains("UnionFields cannot contain more than 128 fields")
1022        );
1023    }
1024
1025    #[test]
1026    fn test_union_fields_try_from_fields_max_valid() {
1027        let fields: Vec<_> = (0..=i8::MAX)
1028            .map(|i| Field::new(format!("field{}", i), DataType::Int32, false))
1029            .collect();
1030        let res = UnionFields::try_from_fields(fields);
1031        assert!(res.is_ok());
1032        let union_fields = res.unwrap();
1033        assert_eq!(union_fields.len(), 128);
1034        assert_eq!(union_fields.iter().map(|(id, _)| id).min().unwrap(), 0);
1035        assert_eq!(union_fields.iter().map(|(id, _)| id).max().unwrap(), 127);
1036    }
1037
1038    #[test]
1039    fn test_union_fields_try_from_fields_over_max() {
1040        // 129 fields should fail
1041        let fields: Vec<_> = (0..129)
1042            .map(|i| Field::new(format!("field{}", i), DataType::Int32, false))
1043            .collect();
1044        let res = UnionFields::try_from_fields(fields);
1045        assert!(res.is_err());
1046    }
1047
1048    #[test]
1049    fn test_union_fields_try_from_fields_complex_types() {
1050        let res = UnionFields::try_from_fields(vec![
1051            Field::new(
1052                "struct_field",
1053                DataType::Struct(Fields::from(vec![
1054                    Field::new("a", DataType::Int32, false),
1055                    Field::new("b", DataType::Utf8, true),
1056                ])),
1057                false,
1058            ),
1059            Field::new_list(
1060                "list_field",
1061                Field::new("item", DataType::Float64, true),
1062                true,
1063            ),
1064            Field::new(
1065                "dict_field",
1066                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1067                false,
1068            ),
1069        ]);
1070        assert!(res.is_ok());
1071        assert_eq!(res.unwrap().len(), 3);
1072    }
1073
1074    #[test]
1075    #[should_panic(
1076        expected = "invalid arguments passed: InvalidArgumentError(\"type ids must be non-negative: -1\")"
1077    )]
1078    fn test_union_fields_from_iter_should_validate() {
1079        let fields: Vec<(i8, FieldRef)> = vec![
1080            (0, Arc::new(Field::new("a", DataType::Int32, true))),
1081            (-1, Arc::new(Field::new("a", DataType::Int32, true))),
1082        ];
1083        UnionFields::from_iter(fields);
1084    }
1085
1086    #[cfg(feature = "serde")]
1087    #[test]
1088    fn test_union_fields_serde_round_trip() {
1089        let fields = UnionFields::try_new(
1090            vec![1, 3],
1091            vec![
1092                Field::new("a", DataType::Int32, true),
1093                Field::new("b", DataType::Utf8, true),
1094            ],
1095        )
1096        .unwrap();
1097        let serialized = postcard::to_stdvec(&fields).unwrap();
1098        let deserialized: UnionFields = postcard::from_bytes(&serialized).unwrap();
1099        assert_eq!(fields, deserialized);
1100    }
1101
1102    #[cfg(feature = "serde")]
1103    #[test]
1104    fn test_union_fields_deserialize_should_validate() {
1105        let field = Arc::new(Field::new("a", DataType::Int32, true));
1106
1107        let duplicate: Vec<(i8, FieldRef)> = vec![(1, Arc::clone(&field)), (1, Arc::clone(&field))];
1108        let serialized = serde_json::to_string(&duplicate).unwrap();
1109        let err = serde_json::from_str::<UnionFields>(&serialized).unwrap_err();
1110        assert!(err.to_string().contains("duplicate type id: 1"), "{err}");
1111
1112        let negative: Vec<(i8, FieldRef)> = vec![(0, Arc::clone(&field)), (-1, field)];
1113        let serialized = serde_json::to_string(&negative).unwrap();
1114        let err = serde_json::from_str::<UnionFields>(&serialized).unwrap_err();
1115        assert!(
1116            err.to_string()
1117                .contains("type ids must be non-negative: -1"),
1118            "{err}"
1119        );
1120    }
1121}