Skip to main content

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