Skip to main content

arrow_schema/
field.rs

1// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: See the NOTICE file distributed with this work for additional information regarding copyright ownership
3// SPDX-FileContributor: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements
4
5use crate::error::ArrowError;
6use std::cmp::Ordering;
7use std::hash::{Hash, Hasher};
8use std::sync::Arc;
9
10use crate::datatype::DataType;
11#[cfg(feature = "canonical_extension_types")]
12use crate::extension::CanonicalExtensionType;
13use crate::schema::SchemaBuilder;
14use crate::{
15    Fields, Metadata, UnionFields, UnionMode,
16    extension::{EXTENSION_TYPE_METADATA_KEY, EXTENSION_TYPE_NAME_KEY, ExtensionType},
17};
18
19/// A reference counted [`Field`]
20pub type FieldRef = Arc<Field>;
21
22/// Describes a single column in a [`Schema`](super::Schema).
23///
24/// A [`Schema`](super::Schema) is an ordered collection of
25/// [`Field`] objects. Fields contain:
26/// * `name`: the name of the field
27/// * `data_type`: the type of the field
28/// * `nullable`: if the field is nullable
29/// * `metadata`: a map of key-value pairs containing additional custom metadata
30///
31/// Arrow Extension types, are encoded in `Field`s metadata. See
32/// [`Self::try_extension_type`] to retrieve the [`ExtensionType`], if any.
33#[derive(Clone)]
34#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
35pub struct Field {
36    name: String,
37    data_type: DataType,
38    nullable: bool,
39    #[deprecated(
40        since = "54.0.0",
41        note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
42    )]
43    dict_id: i64,
44    dict_is_ordered: bool,
45    /// A map of key-value pairs containing additional custom meta data.
46    metadata: Metadata,
47}
48
49impl std::fmt::Debug for Field {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        #![expect(deprecated)] // Must still print dict_id, if set
52        let Self {
53            name,
54            data_type,
55            nullable,
56            dict_id,
57            dict_is_ordered,
58            metadata,
59        } = self;
60
61        let mut s = f.debug_struct("Field");
62
63        if name != "item" {
64            // Keep it short when debug-formatting `DataType::List`
65            s.field("name", name);
66        }
67
68        s.field("data_type", data_type);
69
70        if *nullable {
71            s.field("nullable", nullable);
72        }
73
74        if *dict_id != 0 {
75            s.field("dict_id", dict_id);
76        }
77
78        if *dict_is_ordered {
79            s.field("dict_is_ordered", dict_is_ordered);
80        }
81
82        if !metadata.is_empty() {
83            s.field("metadata", metadata);
84        }
85        s.finish()
86    }
87}
88
89// Auto-derive `PartialEq` traits will pull `dict_id` and `dict_is_ordered`
90// into comparison. However, these properties are only used in IPC context
91// for matching dictionary encoded data. They are not necessary to be same
92// to consider schema equality. For example, in C++ `Field` implementation,
93// it doesn't contain these dictionary properties too.
94impl PartialEq for Field {
95    fn eq(&self, other: &Self) -> bool {
96        self.name == other.name
97            && self.data_type == other.data_type
98            && self.nullable == other.nullable
99            && self.metadata == other.metadata
100    }
101}
102
103impl Eq for Field {}
104
105impl PartialOrd for Field {
106    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
107        Some(self.cmp(other))
108    }
109}
110
111impl Ord for Field {
112    fn cmp(&self, other: &Self) -> Ordering {
113        self.name
114            .cmp(other.name())
115            .then_with(|| self.data_type.cmp(other.data_type()))
116            .then_with(|| self.nullable.cmp(&other.nullable))
117            .then_with(|| self.metadata.cmp(&other.metadata))
118    }
119}
120
121impl Hash for Field {
122    fn hash<H: Hasher>(&self, state: &mut H) {
123        self.name.hash(state);
124        self.data_type.hash(state);
125        self.nullable.hash(state);
126        // `Metadata` iterates in deterministic (sorted) key order
127        self.metadata.hash(state);
128    }
129}
130
131impl AsRef<Field> for Field {
132    fn as_ref(&self) -> &Field {
133        self
134    }
135}
136
137impl Field {
138    /// Default list member field name
139    pub const LIST_FIELD_DEFAULT_NAME: &'static str = "item";
140    /// Default field name for the entries field for Map
141    ///
142    /// See [Arrow Spec](https://github.com/apache/arrow/blob/b19c4761b558ade94ae05743062d92aacedef10e/format/Schema.fbs#L127-L138))
143    pub const MAP_ENTRIES_FIELD_DEFAULT_NAME: &'static str = "entries";
144    /// Default field name for the key field for Map
145    ///
146    /// See [Arrow Spec](https://github.com/apache/arrow/blob/b19c4761b558ade94ae05743062d92aacedef10e/format/Schema.fbs#L127-L138))
147    pub const MAP_KEY_FIELD_DEFAULT_NAME: &'static str = "key";
148    /// Default field name for the value field for Map
149    ///
150    /// See [Arrow Spec](https://github.com/apache/arrow/blob/b19c4761b558ade94ae05743062d92aacedef10e/format/Schema.fbs#L127-L138))
151    pub const MAP_VALUE_FIELD_DEFAULT_NAME: &'static str = "value";
152    /// Default field name for the run-ends field for RunEndEncoded
153    ///
154    /// See [Arrow Spec](https://arrow.apache.org/docs/format/Columnar.html#run-end-encoded-layout)
155    pub const REE_RUN_ENDS_FIELD_DEFAULT_NAME: &'static str = "run_ends";
156    /// Default field name for the values field for RunEndEncoded
157    ///
158    /// See [Arrow Spec](https://arrow.apache.org/docs/format/Columnar.html#run-end-encoded-layout)
159    pub const REE_VALUES_FIELD_DEFAULT_NAME: &'static str = "values";
160
161    /// Creates a new field with the given name, data type, and nullability
162    ///
163    /// # Example
164    /// ```
165    /// # use arrow_schema::{Field, DataType};
166    /// Field::new("field_name", DataType::Int32, true);
167    /// ```
168    pub fn new(name: impl Into<String>, data_type: DataType, nullable: bool) -> Self {
169        #[expect(deprecated)]
170        Field {
171            name: name.into(),
172            data_type,
173            nullable,
174            dict_id: 0,
175            dict_is_ordered: false,
176            metadata: Default::default(),
177        }
178    }
179
180    /// Creates a new `Field` suitable for [`DataType::List`] and
181    /// [`DataType::LargeList`]
182    ///
183    /// While not required, this method follows the convention of naming the
184    /// `Field` `"item"`.
185    ///
186    /// # Example
187    /// ```
188    /// # use arrow_schema::{Field, DataType};
189    /// assert_eq!(
190    ///   Field::new("item", DataType::Int32, true),
191    ///   Field::new_list_field(DataType::Int32, true)
192    /// );
193    /// ```
194    pub fn new_list_field(data_type: DataType, nullable: bool) -> Self {
195        Self::new(Self::LIST_FIELD_DEFAULT_NAME, data_type, nullable)
196    }
197
198    /// Creates a new field that has additional dictionary information
199    #[deprecated(
200        since = "54.0.0",
201        note = "The ability to preserve dictionary IDs will be removed. With the dict_id field disappearing this function signature will change by removing the dict_id parameter."
202    )]
203    pub fn new_dict(
204        name: impl Into<String>,
205        data_type: DataType,
206        nullable: bool,
207        dict_id: i64,
208        dict_is_ordered: bool,
209    ) -> Self {
210        #[expect(deprecated)]
211        Field {
212            name: name.into(),
213            data_type,
214            nullable,
215            dict_id,
216            dict_is_ordered,
217            metadata: Default::default(),
218        }
219    }
220
221    /// Create a new [`Field`] with [`DataType::Dictionary`]
222    ///
223    /// Use [`Self::new_dict`] for more advanced dictionary options
224    ///
225    /// # Panics
226    ///
227    /// Panics if [`!key.is_dictionary_key_type`][DataType::is_dictionary_key_type]
228    pub fn new_dictionary(
229        name: impl Into<String>,
230        key: DataType,
231        value: DataType,
232        nullable: bool,
233    ) -> Self {
234        assert!(
235            key.is_dictionary_key_type(),
236            "{key} is not a valid dictionary key"
237        );
238        let data_type = DataType::Dictionary(Box::new(key), Box::new(value));
239        Self::new(name, data_type, nullable)
240    }
241
242    /// Create a new [`Field`] with [`DataType::Struct`]
243    ///
244    /// - `name`: the name of the [`DataType::Struct`] field
245    /// - `fields`: the description of each struct element
246    /// - `nullable`: if the [`DataType::Struct`] array is nullable
247    pub fn new_struct(name: impl Into<String>, fields: impl Into<Fields>, nullable: bool) -> Self {
248        Self::new(name, DataType::Struct(fields.into()), nullable)
249    }
250
251    /// Create a new [`Field`] with [`DataType::List`]
252    ///
253    /// - `name`: the name of the [`DataType::List`] field
254    /// - `value`: the description of each list element
255    /// - `nullable`: if the [`DataType::List`] array is nullable
256    pub fn new_list(name: impl Into<String>, value: impl Into<FieldRef>, nullable: bool) -> Self {
257        Self::new(name, DataType::List(value.into()), nullable)
258    }
259
260    /// Create a new [`Field`] with [`DataType::LargeList`]
261    ///
262    /// - `name`: the name of the [`DataType::LargeList`] field
263    /// - `value`: the description of each list element
264    /// - `nullable`: if the [`DataType::LargeList`] array is nullable
265    pub fn new_large_list(
266        name: impl Into<String>,
267        value: impl Into<FieldRef>,
268        nullable: bool,
269    ) -> Self {
270        Self::new(name, DataType::LargeList(value.into()), nullable)
271    }
272
273    /// Create a new [`Field`] with [`DataType::FixedSizeList`]
274    ///
275    /// - `name`: the name of the [`DataType::FixedSizeList`] field
276    /// - `value`: the description of each list element
277    /// - `size`: the size of the fixed size list
278    /// - `nullable`: if the [`DataType::FixedSizeList`] array is nullable
279    pub fn new_fixed_size_list(
280        name: impl Into<String>,
281        value: impl Into<FieldRef>,
282        size: i32,
283        nullable: bool,
284    ) -> Self {
285        Self::new(name, DataType::FixedSizeList(value.into(), size), nullable)
286    }
287
288    /// Create a new [`Field`] with [`DataType::Map`]
289    ///
290    /// - `name`: the name of the [`DataType::Map`] field
291    /// - `entries`: the name of the inner [`DataType::Struct`] field
292    /// - `keys`: the map keys
293    /// - `values`: the map values
294    /// - `sorted`: if the [`DataType::Map`] array is sorted
295    /// - `nullable`: if the [`DataType::Map`] array is nullable
296    pub fn new_map(
297        name: impl Into<String>,
298        entries: impl Into<String>,
299        keys: impl Into<FieldRef>,
300        values: impl Into<FieldRef>,
301        sorted: bool,
302        nullable: bool,
303    ) -> Self {
304        let data_type = DataType::Map(
305            Arc::new(Field::new(
306                entries.into(),
307                DataType::Struct(Fields::from([keys.into(), values.into()])),
308                false, // The inner map field is always non-nullable (#1697),
309            )),
310            sorted,
311        );
312        Self::new(name, data_type, nullable)
313    }
314
315    /// Create a new [`Field`] with [`DataType::Union`]
316    ///
317    /// - `name`: the name of the [`DataType::Union`] field
318    /// - `type_ids`: the union type ids
319    /// - `fields`: the union fields
320    /// - `mode`: the union mode
321    ///
322    /// # Panics
323    ///
324    /// Panics if:
325    /// - any type ID is negative
326    /// - type IDs contain duplicates
327    /// - the number of type IDs does not equal the number of fields
328    pub fn new_union<S, F, T>(name: S, type_ids: T, fields: F, mode: UnionMode) -> Self
329    where
330        S: Into<String>,
331        F: IntoIterator,
332        F::Item: Into<FieldRef>,
333        T: IntoIterator<Item = i8>,
334    {
335        Self::new(
336            name,
337            DataType::Union(
338                UnionFields::try_new(type_ids, fields).expect("Invalid UnionField"),
339                mode,
340            ),
341            false, // Unions cannot be nullable
342        )
343    }
344
345    /// Sets the `Field`'s optional custom metadata.
346    #[inline]
347    pub fn set_metadata(&mut self, metadata: impl Into<Metadata>) {
348        self.metadata = metadata.into();
349    }
350
351    /// Sets the metadata of this `Field` to be `metadata` and returns self
352    pub fn with_metadata(mut self, metadata: impl Into<Metadata>) -> Self {
353        self.set_metadata(metadata);
354        self
355    }
356
357    /// Returns the immutable reference to the `Field`'s optional custom metadata.
358    #[inline]
359    pub const fn metadata(&self) -> &Metadata {
360        &self.metadata
361    }
362
363    /// Returns a mutable reference to the `Field`'s optional custom metadata.
364    #[inline]
365    pub fn metadata_mut(&mut self) -> &mut Metadata {
366        &mut self.metadata
367    }
368
369    /// Returns an immutable reference to the `Field`'s name.
370    #[inline]
371    pub const fn name(&self) -> &String {
372        &self.name
373    }
374
375    /// Set the name of this [`Field`]
376    #[inline]
377    pub fn set_name(&mut self, name: impl Into<String>) {
378        self.name = name.into();
379    }
380
381    /// Set the name of the [`Field`] and returns self.
382    ///
383    /// ```
384    /// # use arrow_schema::*;
385    /// let field = Field::new("c1", DataType::Int64, false)
386    ///    .with_name("c2");
387    ///
388    /// assert_eq!(field.name(), "c2");
389    /// ```
390    pub fn with_name(mut self, name: impl Into<String>) -> Self {
391        self.set_name(name);
392        self
393    }
394
395    /// Returns an immutable reference to the [`Field`]'s  [`DataType`].
396    #[inline]
397    pub const fn data_type(&self) -> &DataType {
398        &self.data_type
399    }
400
401    /// Set [`DataType`] of the [`Field`]
402    ///
403    /// ```
404    /// # use arrow_schema::*;
405    /// let mut field = Field::new("c1", DataType::Int64, false);
406    /// field.set_data_type(DataType::Utf8);
407    ///
408    /// assert_eq!(field.data_type(), &DataType::Utf8);
409    /// ```
410    #[inline]
411    pub fn set_data_type(&mut self, data_type: DataType) {
412        self.data_type = data_type;
413    }
414
415    /// Set [`DataType`] of the [`Field`] and returns self.
416    ///
417    /// ```
418    /// # use arrow_schema::*;
419    /// let field = Field::new("c1", DataType::Int64, false)
420    ///    .with_data_type(DataType::Utf8);
421    ///
422    /// assert_eq!(field.data_type(), &DataType::Utf8);
423    /// ```
424    pub fn with_data_type(mut self, data_type: DataType) -> Self {
425        self.set_data_type(data_type);
426        self
427    }
428
429    /// Returns the extension type name of this [`Field`], if set.
430    ///
431    /// This returns the value of [`EXTENSION_TYPE_NAME_KEY`], if set in
432    /// [`Field::metadata`]. If the key is missing, there is no extension type
433    /// name and this returns `None`.
434    ///
435    /// # Example
436    ///
437    /// ```
438    /// # use arrow_schema::{DataType, extension::EXTENSION_TYPE_NAME_KEY, Field};
439    ///
440    /// let field = Field::new("", DataType::Null, false);
441    /// assert_eq!(field.extension_type_name(), None);
442    ///
443    /// let field = Field::new("", DataType::Null, false)
444    ///     .with_metadata([(EXTENSION_TYPE_NAME_KEY, "example")]);
445    /// assert_eq!(field.extension_type_name(), Some("example"));
446    /// ```
447    pub fn extension_type_name(&self) -> Option<&str> {
448        self.metadata()
449            .get(EXTENSION_TYPE_NAME_KEY)
450            .map(String::as_ref)
451    }
452
453    /// Returns the extension type metadata of this [`Field`], if set.
454    ///
455    /// This returns the value of [`EXTENSION_TYPE_METADATA_KEY`], if set in
456    /// [`Field::metadata`]. If the key is missing, there is no extension type
457    /// metadata and this returns `None`.
458    ///
459    /// # Example
460    ///
461    /// ```
462    /// # use arrow_schema::{DataType, extension::EXTENSION_TYPE_METADATA_KEY, Field};
463    ///
464    /// let field = Field::new("", DataType::Null, false);
465    /// assert_eq!(field.extension_type_metadata(), None);
466    ///
467    /// let field = Field::new("", DataType::Null, false)
468    ///     .with_metadata([(EXTENSION_TYPE_METADATA_KEY, "example")]);
469    /// assert_eq!(field.extension_type_metadata(), Some("example"));
470    /// ```
471    pub fn extension_type_metadata(&self) -> Option<&str> {
472        self.metadata()
473            .get(EXTENSION_TYPE_METADATA_KEY)
474            .map(String::as_ref)
475    }
476
477    /// Returns `true` if this [`Field`] has the given [`ExtensionType`] name
478    /// and can be successfully validated as that extension type.
479    ///
480    /// This first checks the extension type name and only calls
481    /// [`ExtensionType::validate`] when the name matches.
482    ///
483    /// This is useful when you only need a boolean validity check and do not
484    /// need to retrieve the extension type instance.
485    #[inline]
486    pub fn has_valid_extension_type<E: ExtensionType>(&self) -> bool {
487        if self.extension_type_name() != Some(E::NAME) {
488            return false;
489        }
490
491        let ext_metadata = self
492            .metadata()
493            .get(EXTENSION_TYPE_METADATA_KEY)
494            .map(|s| s.as_str());
495
496        E::deserialize_metadata(ext_metadata)
497            .and_then(|metadata| E::validate(self.data_type(), metadata))
498            .is_ok()
499    }
500
501    /// Returns an instance of the given [`ExtensionType`] of this [`Field`],
502    /// if set in the [`Field::metadata`].
503    ///
504    /// Note that using `try_extension_type` with an extension type that does
505    /// not match the name in the metadata will return an `ArrowError` which can
506    /// be slow due to string allocations. If you only want to check if a
507    /// [`Field`] has a specific [`ExtensionType`], first check
508    /// [`Field::extension_type_name`], or use [`Field::has_valid_extension_type`]
509    /// to also validate metadata and data type.
510    ///
511    /// # Errors
512    ///
513    /// Returns an error if
514    /// - this field does not have the name of this extension type
515    ///   ([`ExtensionType::NAME`]) in the [`Field::metadata`] (mismatch or
516    ///   missing)
517    /// - the deserialization of the metadata
518    ///   ([`ExtensionType::deserialize_metadata`]) fails
519    /// - the construction of the extension type ([`ExtensionType::try_new`])
520    ///   fail (for example when the [`Field::data_type`] is not supported by
521    ///   the extension type ([`ExtensionType::supports_data_type`]))
522    ///
523    /// # Example: Check and retrieve an extension type
524    /// You can use this to check if a [`Field`] has a specific
525    /// [`ExtensionType`] and retrieve it:
526    /// ```
527    /// # use arrow_schema::{DataType, Field, ArrowError};
528    /// # use arrow_schema::extension::ExtensionType;
529    /// # struct MyExtensionType;
530    /// # impl ExtensionType for MyExtensionType {
531    /// # const NAME: &'static str = "my_extension";
532    /// # type Metadata = String;
533    /// # fn supports_data_type(&self, data_type: &DataType) -> Result<(), ArrowError> { Ok(()) }
534    /// # fn try_new(data_type: &DataType, metadata: Self::Metadata) -> Result<Self, ArrowError> { Ok(Self) }
535    /// # fn serialize_metadata(&self) -> Option<String> { unimplemented!() }
536    /// # fn deserialize_metadata(s: Option<&str>) -> Result<Self::Metadata, ArrowError> { unimplemented!() }
537    /// # fn metadata(&self) -> &<Self as ExtensionType>::Metadata { todo!() }
538    /// # }
539    /// # fn get_field() -> Field { Field::new("field", DataType::Null, false) }
540    /// let field = get_field();
541    /// if let Ok(extension_type) = field.try_extension_type::<MyExtensionType>() {
542    ///   // do something with extension_type
543    /// }
544    /// ```
545    pub fn try_extension_type<E: ExtensionType>(&self) -> Result<E, ArrowError> {
546        E::try_new_from_field_metadata(self.data_type(), self.metadata())
547    }
548
549    /// Returns an instance of the given [`ExtensionType`] of this [`Field`],
550    /// panics if this [`Field`] does not have this extension type.
551    ///
552    /// # Panics
553    ///
554    /// This calls [`Field::try_extension_type`] and panics when it returns an
555    /// error.
556    pub fn extension_type<E: ExtensionType>(&self) -> E {
557        self.try_extension_type::<E>()
558            .unwrap_or_else(|e| panic!("{e}"))
559    }
560
561    /// Updates the metadata of this [`Field`] with the [`ExtensionType::NAME`]
562    /// and [`ExtensionType::metadata`] of the given [`ExtensionType`], if the
563    /// given extension type supports the [`Field::data_type`] of this field
564    /// ([`ExtensionType::supports_data_type`]).
565    ///
566    /// If the given extension type defines no metadata, a previously set
567    /// value of [`EXTENSION_TYPE_METADATA_KEY`] is cleared.
568    ///
569    /// # Error
570    ///
571    /// This functions returns an error if the data type of this field does not
572    /// match any of the supported storage types of the given extension type.
573    pub fn try_with_extension_type<E: ExtensionType>(
574        &mut self,
575        extension_type: E,
576    ) -> Result<(), ArrowError> {
577        // Make sure the data type of this field is supported
578        extension_type.supports_data_type(&self.data_type)?;
579
580        self.metadata
581            .insert(EXTENSION_TYPE_NAME_KEY.to_owned(), E::NAME.to_owned());
582        match extension_type.serialize_metadata() {
583            Some(metadata) => self
584                .metadata
585                .insert(EXTENSION_TYPE_METADATA_KEY.to_owned(), metadata),
586            // If this extension type has no metadata, we make sure to
587            // clear previously set metadata.
588            None => self.metadata.remove(EXTENSION_TYPE_METADATA_KEY),
589        };
590
591        Ok(())
592    }
593
594    /// Updates the metadata of this [`Field`] with the [`ExtensionType::NAME`]
595    /// and [`ExtensionType::metadata`] of the given [`ExtensionType`].
596    ///
597    /// # Panics
598    ///
599    /// This calls [`Field::try_with_extension_type`] and panics when it
600    /// returns an error.
601    pub fn with_extension_type<E: ExtensionType>(mut self, extension_type: E) -> Self {
602        self.try_with_extension_type(extension_type)
603            .unwrap_or_else(|e| panic!("{e}"));
604        self
605    }
606
607    /// Returns the [`CanonicalExtensionType`] of this [`Field`], if set.
608    ///
609    /// # Error
610    ///
611    /// Returns an error if
612    /// - this field does not have a canonical extension type (mismatch or missing)
613    /// - the canonical extension is not supported
614    /// - the construction of the extension type fails
615    #[cfg(feature = "canonical_extension_types")]
616    pub fn try_canonical_extension_type(&self) -> Result<CanonicalExtensionType, ArrowError> {
617        CanonicalExtensionType::try_from(self)
618    }
619
620    /// Indicates whether this [`Field`] supports null values.
621    ///
622    /// If true, the field *may* contain null values.
623    #[inline]
624    pub const fn is_nullable(&self) -> bool {
625        self.nullable
626    }
627
628    /// Set the `nullable` of this [`Field`].
629    ///
630    /// ```
631    /// # use arrow_schema::*;
632    /// let mut field = Field::new("c1", DataType::Int64, false);
633    /// field.set_nullable(true);
634    ///
635    /// assert_eq!(field.is_nullable(), true);
636    /// ```
637    #[inline]
638    pub fn set_nullable(&mut self, nullable: bool) {
639        self.nullable = nullable;
640    }
641
642    /// Set `nullable` of the [`Field`] and returns self.
643    ///
644    /// ```
645    /// # use arrow_schema::*;
646    /// let field = Field::new("c1", DataType::Int64, false)
647    ///    .with_nullable(true);
648    ///
649    /// assert_eq!(field.is_nullable(), true);
650    /// ```
651    pub fn with_nullable(mut self, nullable: bool) -> Self {
652        self.set_nullable(nullable);
653        self
654    }
655
656    /// Returns a (flattened) [`Vec`] containing all child [`Field`]s
657    /// within `self` contained within this field (including `self`)
658    pub(crate) fn fields(&self) -> Vec<&Field> {
659        let mut collected_fields = vec![self];
660        collected_fields.append(&mut Field::_fields(&self.data_type));
661
662        collected_fields
663    }
664
665    fn _fields(dt: &DataType) -> Vec<&Field> {
666        match dt {
667            DataType::Struct(fields) => fields.iter().flat_map(|f| f.fields()).collect(),
668            DataType::Union(fields, _) => fields.iter().flat_map(|(_, f)| f.fields()).collect(),
669            DataType::List(field)
670            | DataType::LargeList(field)
671            | DataType::ListView(field)
672            | DataType::LargeListView(field)
673            | DataType::FixedSizeList(field, _)
674            | DataType::Map(field, _) => field.fields(),
675            DataType::Dictionary(_, value_field) => Field::_fields(value_field.as_ref()),
676            DataType::RunEndEncoded(_, field) => field.fields(),
677            _ => vec![],
678        }
679    }
680
681    /// Returns a vector containing all (potentially nested) `Field` instances selected by the
682    /// dictionary ID they use
683    #[inline]
684    #[deprecated(
685        since = "54.0.0",
686        note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
687    )]
688    pub(crate) fn fields_with_dict_id(&self, id: i64) -> Vec<&Field> {
689        self.fields()
690            .into_iter()
691            .filter(|&field| {
692                #[expect(deprecated)]
693                let matching_dict_id = field.dict_id == id;
694                matches!(field.data_type(), DataType::Dictionary(_, _)) && matching_dict_id
695            })
696            .collect()
697    }
698
699    /// Returns the dictionary ID, if this is a dictionary type.
700    #[inline]
701    #[deprecated(
702        since = "54.0.0",
703        note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
704    )]
705    pub const fn dict_id(&self) -> Option<i64> {
706        match self.data_type {
707            #[expect(deprecated)]
708            DataType::Dictionary(_, _) => Some(self.dict_id),
709            _ => None,
710        }
711    }
712
713    /// Returns whether this `Field`'s dictionary is ordered, if this is a dictionary type.
714    ///
715    /// # Example
716    /// ```
717    /// # use arrow_schema::{DataType, Field};
718    /// // non dictionaries do not have a dict is ordered flat
719    /// let field = Field::new("c1", DataType::Int64, false);
720    /// assert_eq!(field.dict_is_ordered(), None);
721    /// // by default dictionary is not ordered
722    /// let field = Field::new("c1", DataType::Dictionary(Box::new(DataType::Int64), Box::new(DataType::Utf8)), false);
723    /// assert_eq!(field.dict_is_ordered(), Some(false));
724    /// let field = field.with_dict_is_ordered(true);
725    /// assert_eq!(field.dict_is_ordered(), Some(true));
726    /// ```
727    #[inline]
728    pub const fn dict_is_ordered(&self) -> Option<bool> {
729        match self.data_type {
730            DataType::Dictionary(_, _) => Some(self.dict_is_ordered),
731            _ => None,
732        }
733    }
734
735    /// Set the is ordered field for this `Field`, if it is a dictionary.
736    ///
737    /// Does nothing if this is not a dictionary type.
738    ///
739    /// See [`Field::dict_is_ordered`] for more information.
740    pub fn with_dict_is_ordered(mut self, dict_is_ordered: bool) -> Self {
741        if matches!(self.data_type, DataType::Dictionary(_, _)) {
742            self.dict_is_ordered = dict_is_ordered;
743        }
744        self
745    }
746
747    /// Merge this field into self if it is compatible.
748    ///
749    /// Struct fields are merged recursively.
750    ///
751    /// NOTE: `self` may be updated to a partial / unexpected state in case of merge failure.
752    ///
753    /// Example:
754    ///
755    /// ```
756    /// # use arrow_schema::*;
757    /// let mut field = Field::new("c1", DataType::Int64, false);
758    /// assert!(field.try_merge(&Field::new("c1", DataType::Int64, true)).is_ok());
759    /// assert!(field.is_nullable());
760    /// ```
761    pub fn try_merge(&mut self, from: &Field) -> Result<(), ArrowError> {
762        if from.dict_is_ordered != self.dict_is_ordered {
763            return Err(ArrowError::SchemaError(format!(
764                "Fail to merge schema field '{}' because from dict_is_ordered = {} does not match {}",
765                self.name, from.dict_is_ordered, self.dict_is_ordered
766            )));
767        }
768        // merge metadata
769        match (self.metadata().is_empty(), from.metadata().is_empty()) {
770            (false, false) => {
771                let mut merged = self.metadata().clone();
772                for (key, from_value) in from.metadata() {
773                    if let Some(self_value) = self.metadata.get(key) {
774                        if self_value != from_value {
775                            return Err(ArrowError::SchemaError(format!(
776                                "Fail to merge field '{}' due to conflicting metadata data value for key {}.
777                                    From value = {} does not match {}", self.name, key, from_value, self_value),
778                            ));
779                        }
780                    } else {
781                        merged.insert(key.clone(), from_value.clone());
782                    }
783                }
784                self.set_metadata(merged);
785            }
786            (true, false) => {
787                self.set_metadata(from.metadata().clone());
788            }
789            _ => {}
790        }
791        match &mut self.data_type {
792            DataType::Struct(nested_fields) => match &from.data_type {
793                DataType::Struct(from_nested_fields) => {
794                    let mut builder = SchemaBuilder::new();
795                    nested_fields
796                        .iter()
797                        .chain(from_nested_fields)
798                        .try_for_each(|f| builder.try_merge(f))?;
799                    *nested_fields = builder.finish().fields;
800                }
801                DataType::Null => {
802                    self.nullable = true;
803                }
804                _ => {
805                    return Err(ArrowError::SchemaError(format!(
806                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Struct",
807                        self.name, from.data_type
808                    )));
809                }
810            },
811            DataType::Union(nested_fields, mode) => match &from.data_type {
812                DataType::Union(from_nested_fields, from_mode) => {
813                    if mode != from_mode {
814                        return Err(ArrowError::SchemaError(format!(
815                            "Fail to merge schema field '{}' because the from union mode = {:?} does not match {:?}",
816                            self.name, from_mode, mode
817                        )));
818                    }
819                    nested_fields.try_merge(from_nested_fields)?;
820                }
821                DataType::Null => {
822                    self.nullable = true;
823                }
824                _ => {
825                    return Err(ArrowError::SchemaError(format!(
826                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Union",
827                        self.name, from.data_type
828                    )));
829                }
830            },
831            DataType::List(field) => match &from.data_type {
832                DataType::List(from_field) => {
833                    let mut f = (**field).clone();
834                    f.try_merge(from_field)?;
835                    (*field) = Arc::new(f);
836                }
837                DataType::Null => {
838                    self.nullable = true;
839                }
840                _ => {
841                    return Err(ArrowError::SchemaError(format!(
842                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::List",
843                        self.name, from.data_type
844                    )));
845                }
846            },
847            DataType::LargeList(field) => match &from.data_type {
848                DataType::LargeList(from_field) => {
849                    let mut f = (**field).clone();
850                    f.try_merge(from_field)?;
851                    (*field) = Arc::new(f);
852                }
853                DataType::Null => {
854                    self.nullable = true;
855                }
856                _ => {
857                    return Err(ArrowError::SchemaError(format!(
858                        "Fail to merge schema field '{}' because the from data_type = {} is not DataType::LargeList",
859                        self.name, from.data_type
860                    )));
861                }
862            },
863            DataType::Null => {
864                self.nullable = true;
865                self.data_type = from.data_type.clone();
866            }
867            DataType::Boolean
868            | DataType::Int8
869            | DataType::Int16
870            | DataType::Int32
871            | DataType::Int64
872            | DataType::UInt8
873            | DataType::UInt16
874            | DataType::UInt32
875            | DataType::UInt64
876            | DataType::Float16
877            | DataType::Float32
878            | DataType::Float64
879            | DataType::Timestamp(_, _)
880            | DataType::Date32
881            | DataType::Date64
882            | DataType::Time32(_)
883            | DataType::Time64(_)
884            | DataType::Duration(_)
885            | DataType::Binary
886            | DataType::LargeBinary
887            | DataType::BinaryView
888            | DataType::Interval(_)
889            | DataType::LargeListView(_)
890            | DataType::ListView(_)
891            | DataType::Map(_, _)
892            | DataType::Dictionary(_, _)
893            | DataType::RunEndEncoded(_, _)
894            | DataType::FixedSizeList(_, _)
895            | DataType::FixedSizeBinary(_)
896            | DataType::Utf8
897            | DataType::LargeUtf8
898            | DataType::Utf8View
899            | DataType::Decimal32(_, _)
900            | DataType::Decimal64(_, _)
901            | DataType::Decimal128(_, _)
902            | DataType::Decimal256(_, _) => {
903                if from.data_type == DataType::Null {
904                    self.nullable = true;
905                } else if self.data_type != from.data_type {
906                    return Err(ArrowError::SchemaError(format!(
907                        "Fail to merge schema field '{}' because the from data_type = {} does not equal {}",
908                        self.name, from.data_type, self.data_type
909                    )));
910                }
911            }
912        }
913        self.nullable |= from.nullable;
914
915        Ok(())
916    }
917
918    /// Check to see if `self` is a superset of `other` field. Superset is defined as:
919    ///
920    /// * if nullability doesn't match, self needs to be nullable
921    /// * self.metadata is a superset of other.metadata
922    /// * all other fields are equal
923    pub fn contains(&self, other: &Field) -> bool {
924        self.name == other.name
925        && self.data_type.contains(&other.data_type)
926        && self.dict_is_ordered == other.dict_is_ordered
927        // self need to be nullable or both of them are not nullable
928        && (self.nullable || !other.nullable)
929        // make sure self.metadata is a superset of other.metadata
930        && other.metadata.iter().all(|(k, v1)| {
931            self.metadata.get(k).is_some_and(|v2| v1 == v2)
932        })
933    }
934
935    /// Return size of this instance in bytes.
936    ///
937    /// Includes the size of `Self`.
938    pub fn size(&self) -> usize {
939        std::mem::size_of_val(self) - std::mem::size_of_val(&self.data_type)
940            + self.data_type.size()
941            + self.name.capacity()
942            + (std::mem::size_of::<(String, String)>() * self.metadata.len())
943            + self
944                .metadata
945                .iter()
946                .map(|(k, v)| k.capacity() + v.capacity())
947                .sum::<usize>()
948    }
949}
950
951impl std::fmt::Display for Field {
952    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
953        #![expect(deprecated)] // Must still print dict_id, if set
954        let Self {
955            name,
956            data_type,
957            nullable,
958            dict_id,
959            dict_is_ordered,
960            metadata,
961        } = self;
962        let maybe_nullable = if *nullable { "nullable " } else { "" };
963        let metadata_str = if metadata.is_empty() {
964            String::new()
965        } else {
966            format!(", metadata: {metadata:?}")
967        };
968        let dict_id_str = if dict_id == &0 {
969            String::new()
970        } else {
971            format!(", dict_id: {dict_id}")
972        };
973        let dict_is_ordered_str = if *dict_is_ordered {
974            ", dict_is_ordered"
975        } else {
976            ""
977        };
978        write!(
979            f,
980            "Field {{ {name:?}: {maybe_nullable}{data_type}{dict_id_str}{dict_is_ordered_str}{metadata_str} }}"
981        )
982    }
983}
984
985#[cfg(test)]
986mod test {
987    use super::*;
988    use std::collections::HashMap;
989    use std::collections::hash_map::DefaultHasher;
990
991    #[derive(Debug, Clone, Copy)]
992    struct TestExtensionType;
993
994    impl ExtensionType for TestExtensionType {
995        const NAME: &'static str = "test.extension";
996        type Metadata = ();
997
998        fn metadata(&self) -> &Self::Metadata {
999            &()
1000        }
1001
1002        fn serialize_metadata(&self) -> Option<String> {
1003            None
1004        }
1005
1006        fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
1007            metadata.map_or(Ok(()), |_| {
1008                Err(ArrowError::InvalidArgumentError(
1009                    "TestExtensionType expects no metadata".to_owned(),
1010                ))
1011            })
1012        }
1013
1014        fn supports_data_type(&self, _data_type: &DataType) -> Result<(), ArrowError> {
1015            Ok(())
1016        }
1017
1018        fn try_new(_data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
1019            Ok(Self)
1020        }
1021    }
1022
1023    #[test]
1024    fn test_has_valid_extension_type() {
1025        let no_extension = Field::new("f", DataType::Null, false);
1026        assert!(!no_extension.has_valid_extension_type::<TestExtensionType>());
1027
1028        let matching_name = Field::new("f", DataType::Null, false)
1029            .with_metadata([(EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME)]);
1030        assert!(matching_name.has_valid_extension_type::<TestExtensionType>());
1031
1032        let matching_name_with_invalid_metadata = Field::new("f", DataType::Null, false)
1033            .with_metadata([
1034                (EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME),
1035                (EXTENSION_TYPE_METADATA_KEY, "invalid"),
1036            ]);
1037        assert!(
1038            !matching_name_with_invalid_metadata.has_valid_extension_type::<TestExtensionType>()
1039        );
1040
1041        let different_name = Field::new("f", DataType::Null, false)
1042            .with_metadata([(EXTENSION_TYPE_NAME_KEY, "some.other_extension")]);
1043        assert!(!different_name.has_valid_extension_type::<TestExtensionType>());
1044    }
1045
1046    #[test]
1047    fn test_new_with_string() {
1048        // Fields should allow owned Strings to support reuse
1049        let s = "c1";
1050        Field::new(s, DataType::Int64, false);
1051    }
1052
1053    #[test]
1054    fn test_new_dict_with_string() {
1055        // Fields should allow owned Strings to support reuse
1056        let s = "c1";
1057        #[expect(deprecated)]
1058        Field::new_dict(s, DataType::Int64, false, 4, false);
1059    }
1060
1061    #[test]
1062    #[cfg_attr(miri, ignore)] // fork is not supported
1063    fn test_debug_format_field() {
1064        // Make sure the `Debug` formatting of `Field` is readable and not too long
1065        insta::assert_debug_snapshot!(Field::new("item", DataType::UInt8, false), @r"
1066        Field {
1067            data_type: UInt8,
1068        }
1069        ");
1070        insta::assert_debug_snapshot!(Field::new("column", DataType::LargeUtf8, true), @r#"
1071        Field {
1072            name: "column",
1073            data_type: LargeUtf8,
1074            nullable: true,
1075        }
1076        "#);
1077    }
1078
1079    #[test]
1080    fn test_merge_union_modes() {
1081        for mode in [UnionMode::Sparse, UnionMode::Dense] {
1082            let mut field = Field::new_union(
1083                "u",
1084                [0],
1085                [Field::new("number", DataType::Int32, false)],
1086                mode,
1087            );
1088            let other_mode = match mode {
1089                UnionMode::Sparse => UnionMode::Dense,
1090                UnionMode::Dense => UnionMode::Sparse,
1091            };
1092            let incompatible = Field::new_union(
1093                "u",
1094                [0],
1095                [Field::new("number", DataType::Int32, false)],
1096                other_mode,
1097            );
1098            assert!(matches!(
1099                field.try_merge(&incompatible),
1100                Err(ArrowError::SchemaError(_))
1101            ));
1102
1103            let compatible =
1104                Field::new_union("u", [1], [Field::new("text", DataType::Utf8, false)], mode);
1105            field.try_merge(&compatible).unwrap();
1106            let expected = Field::new_union(
1107                "u",
1108                [0, 1],
1109                [
1110                    Field::new("number", DataType::Int32, false),
1111                    Field::new("text", DataType::Utf8, false),
1112                ],
1113                mode,
1114            );
1115            assert_eq!(field, expected);
1116        }
1117    }
1118
1119    #[test]
1120    fn test_merge_incompatible_types() {
1121        let mut field = Field::new("c1", DataType::Int64, false);
1122        let result = field
1123            .try_merge(&Field::new("c1", DataType::Float32, true))
1124            .expect_err("should fail")
1125            .to_string();
1126        assert_eq!(
1127            "Schema error: Fail to merge schema field 'c1' because the from data_type = Float32 does not equal Int64",
1128            result
1129        );
1130    }
1131
1132    #[test]
1133    fn test_merge_with_null() {
1134        let mut field1 = Field::new("c1", DataType::Null, true);
1135        field1
1136            .try_merge(&Field::new("c1", DataType::Float32, false))
1137            .expect("should widen type to nullable float");
1138        assert_eq!(Field::new("c1", DataType::Float32, true), field1);
1139
1140        let mut field2 = Field::new("c2", DataType::Utf8, false);
1141        field2
1142            .try_merge(&Field::new("c2", DataType::Null, true))
1143            .expect("should widen type to nullable utf8");
1144        assert_eq!(Field::new("c2", DataType::Utf8, true), field2);
1145    }
1146
1147    #[test]
1148    fn test_merge_with_nested_null() {
1149        let mut struct1 = Field::new(
1150            "s1",
1151            DataType::Struct(Fields::from(vec![Field::new(
1152                "inner",
1153                DataType::Float32,
1154                false,
1155            )])),
1156            false,
1157        );
1158
1159        let struct2 = Field::new(
1160            "s2",
1161            DataType::Struct(Fields::from(vec![Field::new(
1162                "inner",
1163                DataType::Null,
1164                false,
1165            )])),
1166            true,
1167        );
1168
1169        struct1
1170            .try_merge(&struct2)
1171            .expect("should widen inner field's type to nullable float");
1172        assert_eq!(
1173            Field::new(
1174                "s1",
1175                DataType::Struct(Fields::from(vec![Field::new(
1176                    "inner",
1177                    DataType::Float32,
1178                    true,
1179                )])),
1180                true,
1181            ),
1182            struct1
1183        );
1184
1185        let mut list1 = Field::new(
1186            "l1",
1187            DataType::List(Field::new("inner", DataType::Float32, false).into()),
1188            false,
1189        );
1190
1191        let list2 = Field::new(
1192            "l2",
1193            DataType::List(Field::new("inner", DataType::Null, false).into()),
1194            true,
1195        );
1196
1197        list1
1198            .try_merge(&list2)
1199            .expect("should widen inner field's type to nullable float");
1200        assert_eq!(
1201            Field::new(
1202                "l1",
1203                DataType::List(Field::new("inner", DataType::Float32, true).into()),
1204                true,
1205            ),
1206            list1
1207        );
1208
1209        let mut large_list1 = Field::new(
1210            "ll1",
1211            DataType::LargeList(Field::new("inner", DataType::Float32, false).into()),
1212            false,
1213        );
1214
1215        let large_list2 = Field::new(
1216            "ll2",
1217            DataType::LargeList(Field::new("inner", DataType::Null, false).into()),
1218            true,
1219        );
1220
1221        large_list1
1222            .try_merge(&large_list2)
1223            .expect("should widen inner field's type to nullable float");
1224        assert_eq!(
1225            Field::new(
1226                "ll1",
1227                DataType::LargeList(Field::new("inner", DataType::Float32, true).into()),
1228                true,
1229            ),
1230            large_list1
1231        );
1232    }
1233
1234    #[test]
1235    fn test_fields_with_dict_id() {
1236        #[expect(deprecated)]
1237        let dict1 = Field::new_dict(
1238            "dict1",
1239            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1240            false,
1241            10,
1242            false,
1243        );
1244        #[expect(deprecated)]
1245        let dict2 = Field::new_dict(
1246            "dict2",
1247            DataType::Dictionary(DataType::Int32.into(), DataType::Int8.into()),
1248            false,
1249            20,
1250            false,
1251        );
1252
1253        let field = Field::new(
1254            "struct<dict1, list[struct<dict2, list[struct<dict1]>]>",
1255            DataType::Struct(Fields::from(vec![
1256                dict1.clone(),
1257                Field::new(
1258                    "list[struct<dict1, list[struct<dict2>]>]",
1259                    DataType::List(Arc::new(Field::new(
1260                        "struct<dict1, list[struct<dict2>]>",
1261                        DataType::Struct(Fields::from(vec![
1262                            dict1.clone(),
1263                            Field::new(
1264                                "list[struct<dict2>]",
1265                                DataType::List(Arc::new(Field::new(
1266                                    "struct<dict2>",
1267                                    DataType::Struct(vec![dict2.clone()].into()),
1268                                    false,
1269                                ))),
1270                                false,
1271                            ),
1272                        ])),
1273                        false,
1274                    ))),
1275                    false,
1276                ),
1277            ])),
1278            false,
1279        );
1280
1281        #[expect(deprecated)]
1282        for field in field.fields_with_dict_id(10) {
1283            assert_eq!(dict1, *field);
1284        }
1285        #[expect(deprecated)]
1286        for field in field.fields_with_dict_id(20) {
1287            assert_eq!(dict2, *field);
1288        }
1289    }
1290
1291    fn get_field_hash(field: &Field) -> u64 {
1292        let mut s = DefaultHasher::new();
1293        field.hash(&mut s);
1294        s.finish()
1295    }
1296
1297    #[test]
1298    fn test_field_comparison_case() {
1299        // dictionary-encoding properties not used for field comparison
1300        #[expect(deprecated)]
1301        let dict1 = Field::new_dict(
1302            "dict1",
1303            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1304            false,
1305            10,
1306            false,
1307        );
1308        #[expect(deprecated)]
1309        let dict2 = Field::new_dict(
1310            "dict1",
1311            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1312            false,
1313            20,
1314            false,
1315        );
1316
1317        assert_eq!(dict1, dict2);
1318        assert_eq!(get_field_hash(&dict1), get_field_hash(&dict2));
1319
1320        #[expect(deprecated)]
1321        let dict1 = Field::new_dict(
1322            "dict0",
1323            DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1324            false,
1325            10,
1326            false,
1327        );
1328
1329        assert_ne!(dict1, dict2);
1330        assert_ne!(get_field_hash(&dict1), get_field_hash(&dict2));
1331    }
1332
1333    #[test]
1334    fn test_field_comparison_metadata() {
1335        let f1 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1336            (String::from("k1"), String::from("v1")),
1337            (String::from("k2"), String::from("v2")),
1338        ]));
1339        let f2 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1340            (String::from("k1"), String::from("v1")),
1341            (String::from("k3"), String::from("v3")),
1342        ]));
1343        let f3 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1344            (String::from("k1"), String::from("v1")),
1345            (String::from("k3"), String::from("v4")),
1346        ]));
1347
1348        assert!(f1.cmp(&f2).is_lt());
1349        assert!(f2.cmp(&f3).is_lt());
1350        assert!(f1.cmp(&f3).is_lt());
1351    }
1352
1353    #[test]
1354    #[expect(clippy::needless_borrows_for_generic_args)] // intentional to exercise various references
1355    fn test_field_as_ref() {
1356        let field = || Field::new("x", DataType::Binary, false);
1357
1358        // AsRef can be used in a function accepting a field.
1359        // However, this case actually works a bit better when function takes `&Field`
1360        fn accept_ref(_: impl AsRef<Field>) {}
1361
1362        accept_ref(field());
1363        accept_ref(&field());
1364        accept_ref(&&field());
1365        accept_ref(Arc::new(field()));
1366        accept_ref(&Arc::new(field()));
1367        accept_ref(&&Arc::new(field()));
1368
1369        // AsRef can be used in a function accepting a collection of fields in any form,
1370        // such as &[Field], or &[Arc<Field>]
1371        fn accept_refs(_: impl IntoIterator<Item: AsRef<Field>>) {}
1372
1373        accept_refs(vec![field()]);
1374        accept_refs(vec![&field()]);
1375        accept_refs(vec![Arc::new(field())]);
1376        accept_refs(vec![&Arc::new(field())]);
1377        accept_refs(&vec![field()]);
1378        accept_refs(&vec![&field()]);
1379        accept_refs(&vec![Arc::new(field())]);
1380        accept_refs(&vec![&Arc::new(field())]);
1381    }
1382
1383    #[test]
1384    fn test_contains_reflexivity() {
1385        let mut field = Field::new("field1", DataType::Float16, false);
1386        field.set_metadata(HashMap::from([
1387            (String::from("k0"), String::from("v0")),
1388            (String::from("k1"), String::from("v1")),
1389        ]));
1390        assert!(field.contains(&field))
1391    }
1392
1393    #[test]
1394    fn test_contains_transitivity() {
1395        let child_field = Field::new("child1", DataType::Float16, false);
1396
1397        let mut field1 = Field::new(
1398            "field1",
1399            DataType::Struct(Fields::from(vec![child_field])),
1400            false,
1401        );
1402        field1.set_metadata(HashMap::from([(String::from("k1"), String::from("v1"))]));
1403
1404        let mut field2 = Field::new("field1", DataType::Struct(Fields::default()), true);
1405        field2.set_metadata(HashMap::from([(String::from("k2"), String::from("v2"))]));
1406        field2.try_merge(&field1).unwrap();
1407
1408        let mut field3 = Field::new("field1", DataType::Struct(Fields::default()), false);
1409        field3.set_metadata(HashMap::from([(String::from("k3"), String::from("v3"))]));
1410        field3.try_merge(&field2).unwrap();
1411
1412        assert!(field2.contains(&field1));
1413        assert!(field3.contains(&field2));
1414        assert!(field3.contains(&field1));
1415
1416        assert!(!field1.contains(&field2));
1417        assert!(!field1.contains(&field3));
1418        assert!(!field2.contains(&field3));
1419    }
1420
1421    #[test]
1422    fn test_contains_nullable() {
1423        let field1 = Field::new("field1", DataType::Boolean, true);
1424        let field2 = Field::new("field1", DataType::Boolean, false);
1425        assert!(field1.contains(&field2));
1426        assert!(!field2.contains(&field1));
1427    }
1428
1429    #[test]
1430    fn test_contains_must_have_same_fields() {
1431        let child_field1 = Field::new("child1", DataType::Float16, false);
1432        let child_field2 = Field::new("child2", DataType::Float16, false);
1433
1434        let field1 = Field::new(
1435            "field1",
1436            DataType::Struct(vec![child_field1.clone()].into()),
1437            true,
1438        );
1439        let field2 = Field::new(
1440            "field1",
1441            DataType::Struct(vec![child_field1, child_field2].into()),
1442            true,
1443        );
1444
1445        assert!(!field1.contains(&field2));
1446        assert!(!field2.contains(&field1));
1447
1448        // UnionFields with different type ID
1449        let field1 = Field::new(
1450            "field1",
1451            DataType::Union(
1452                UnionFields::try_new(
1453                    vec![1, 2],
1454                    vec![
1455                        Field::new("field1", DataType::UInt8, true),
1456                        Field::new("field3", DataType::Utf8, false),
1457                    ],
1458                )
1459                .unwrap(),
1460                UnionMode::Dense,
1461            ),
1462            true,
1463        );
1464        let field2 = Field::new(
1465            "field1",
1466            DataType::Union(
1467                UnionFields::try_new(
1468                    vec![1, 3],
1469                    vec![
1470                        Field::new("field1", DataType::UInt8, false),
1471                        Field::new("field3", DataType::Utf8, false),
1472                    ],
1473                )
1474                .unwrap(),
1475                UnionMode::Dense,
1476            ),
1477            true,
1478        );
1479        assert!(!field1.contains(&field2));
1480
1481        // UnionFields with same type ID
1482        let field1 = Field::new(
1483            "field1",
1484            DataType::Union(
1485                UnionFields::try_new(
1486                    vec![1, 2],
1487                    vec![
1488                        Field::new("field1", DataType::UInt8, true),
1489                        Field::new("field3", DataType::Utf8, false),
1490                    ],
1491                )
1492                .unwrap(),
1493                UnionMode::Dense,
1494            ),
1495            true,
1496        );
1497        let field2 = Field::new(
1498            "field1",
1499            DataType::Union(
1500                UnionFields::try_new(
1501                    vec![1, 2],
1502                    vec![
1503                        Field::new("field1", DataType::UInt8, false),
1504                        Field::new("field3", DataType::Utf8, false),
1505                    ],
1506                )
1507                .unwrap(),
1508                UnionMode::Dense,
1509            ),
1510            true,
1511        );
1512        assert!(field1.contains(&field2));
1513    }
1514
1515    #[cfg(feature = "serde")]
1516    fn assert_binary_serde_round_trip(field: Field) {
1517        let serialized = postcard::to_stdvec(&field).unwrap();
1518        let deserialized: Field = postcard::from_bytes(&serialized).unwrap();
1519        assert_eq!(field, deserialized)
1520    }
1521
1522    #[cfg(feature = "serde")]
1523    #[test]
1524    fn test_field_without_metadata_serde() {
1525        let field = Field::new("name", DataType::Boolean, true);
1526        assert_binary_serde_round_trip(field)
1527    }
1528
1529    #[cfg(feature = "serde")]
1530    #[test]
1531    fn test_field_with_empty_metadata_serde() {
1532        let field = Field::new("name", DataType::Boolean, false).with_metadata(HashMap::new());
1533
1534        assert_binary_serde_round_trip(field)
1535    }
1536
1537    #[cfg(feature = "serde")]
1538    #[test]
1539    fn test_field_with_nonempty_metadata_serde() {
1540        let mut metadata = HashMap::new();
1541        metadata.insert("hi".to_owned(), String::new());
1542        let field = Field::new("name", DataType::Boolean, false).with_metadata(metadata);
1543
1544        assert_binary_serde_round_trip(field)
1545    }
1546
1547    #[test]
1548    fn test_merge_compound_with_null() {
1549        // Struct + Null
1550        let mut field = Field::new(
1551            "s",
1552            DataType::Struct(Fields::from(vec![Field::new("a", DataType::Int32, false)])),
1553            false,
1554        );
1555        field
1556            .try_merge(&Field::new("s", DataType::Null, true))
1557            .expect("Struct should merge with Null");
1558        assert!(field.is_nullable());
1559        assert!(matches!(field.data_type(), DataType::Struct(_)));
1560
1561        // List + Null
1562        let mut field = Field::new(
1563            "l",
1564            DataType::List(Field::new("item", DataType::Utf8, false).into()),
1565            false,
1566        );
1567        field
1568            .try_merge(&Field::new("l", DataType::Null, true))
1569            .expect("List should merge with Null");
1570        assert!(field.is_nullable());
1571        assert!(matches!(field.data_type(), DataType::List(_)));
1572
1573        // LargeList + Null
1574        let mut field = Field::new(
1575            "ll",
1576            DataType::LargeList(Field::new("item", DataType::Utf8, false).into()),
1577            false,
1578        );
1579        field
1580            .try_merge(&Field::new("ll", DataType::Null, true))
1581            .expect("LargeList should merge with Null");
1582        assert!(field.is_nullable());
1583        assert!(matches!(field.data_type(), DataType::LargeList(_)));
1584
1585        // Union + Null
1586        let mut field = Field::new(
1587            "u",
1588            DataType::Union(
1589                UnionFields::try_new(vec![0], vec![Field::new("f", DataType::Int32, false)])
1590                    .unwrap(),
1591                UnionMode::Dense,
1592            ),
1593            false,
1594        );
1595        field
1596            .try_merge(&Field::new("u", DataType::Null, true))
1597            .expect("Union should merge with Null");
1598        assert!(matches!(field.data_type(), DataType::Union(_, _)));
1599    }
1600}