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