1use 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
32pub type FieldRef = Arc<Field>;
34
35#[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 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)] 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 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
102impl 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 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 pub const LIST_FIELD_DEFAULT_NAME: &'static str = "item";
153 pub const MAP_ENTRIES_FIELD_DEFAULT_NAME: &'static str = "entries";
157 pub const MAP_KEY_FIELD_DEFAULT_NAME: &'static str = "key";
161 pub const MAP_VALUE_FIELD_DEFAULT_NAME: &'static str = "value";
165
166 pub fn new(name: impl Into<String>, data_type: DataType, nullable: bool) -> Self {
174 #[allow(deprecated)]
175 Field {
176 name: name.into(),
177 data_type,
178 nullable,
179 dict_id: 0,
180 dict_is_ordered: false,
181 metadata: Default::default(),
182 }
183 }
184
185 pub fn new_list_field(data_type: DataType, nullable: bool) -> Self {
200 Self::new(Self::LIST_FIELD_DEFAULT_NAME, data_type, nullable)
201 }
202
203 #[deprecated(
205 since = "54.0.0",
206 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."
207 )]
208 pub fn new_dict(
209 name: impl Into<String>,
210 data_type: DataType,
211 nullable: bool,
212 dict_id: i64,
213 dict_is_ordered: bool,
214 ) -> Self {
215 #[allow(deprecated)]
216 Field {
217 name: name.into(),
218 data_type,
219 nullable,
220 dict_id,
221 dict_is_ordered,
222 metadata: Default::default(),
223 }
224 }
225
226 pub fn new_dictionary(
234 name: impl Into<String>,
235 key: DataType,
236 value: DataType,
237 nullable: bool,
238 ) -> Self {
239 assert!(
240 key.is_dictionary_key_type(),
241 "{key} is not a valid dictionary key"
242 );
243 let data_type = DataType::Dictionary(Box::new(key), Box::new(value));
244 Self::new(name, data_type, nullable)
245 }
246
247 pub fn new_struct(name: impl Into<String>, fields: impl Into<Fields>, nullable: bool) -> Self {
253 Self::new(name, DataType::Struct(fields.into()), nullable)
254 }
255
256 pub fn new_list(name: impl Into<String>, value: impl Into<FieldRef>, nullable: bool) -> Self {
262 Self::new(name, DataType::List(value.into()), nullable)
263 }
264
265 pub fn new_large_list(
271 name: impl Into<String>,
272 value: impl Into<FieldRef>,
273 nullable: bool,
274 ) -> Self {
275 Self::new(name, DataType::LargeList(value.into()), nullable)
276 }
277
278 pub fn new_fixed_size_list(
285 name: impl Into<String>,
286 value: impl Into<FieldRef>,
287 size: i32,
288 nullable: bool,
289 ) -> Self {
290 Self::new(name, DataType::FixedSizeList(value.into(), size), nullable)
291 }
292
293 pub fn new_map(
302 name: impl Into<String>,
303 entries: impl Into<String>,
304 keys: impl Into<FieldRef>,
305 values: impl Into<FieldRef>,
306 sorted: bool,
307 nullable: bool,
308 ) -> Self {
309 let data_type = DataType::Map(
310 Arc::new(Field::new(
311 entries.into(),
312 DataType::Struct(Fields::from([keys.into(), values.into()])),
313 false, )),
315 sorted,
316 );
317 Self::new(name, data_type, nullable)
318 }
319
320 pub fn new_union<S, F, T>(name: S, type_ids: T, fields: F, mode: UnionMode) -> Self
334 where
335 S: Into<String>,
336 F: IntoIterator,
337 F::Item: Into<FieldRef>,
338 T: IntoIterator<Item = i8>,
339 {
340 Self::new(
341 name,
342 DataType::Union(
343 UnionFields::try_new(type_ids, fields).expect("Invalid UnionField"),
344 mode,
345 ),
346 false, )
348 }
349
350 #[inline]
352 pub fn set_metadata(&mut self, metadata: impl Into<Metadata>) {
353 self.metadata = metadata.into();
354 }
355
356 pub fn with_metadata(mut self, metadata: impl Into<Metadata>) -> Self {
358 self.set_metadata(metadata);
359 self
360 }
361
362 #[inline]
364 pub const fn metadata(&self) -> &Metadata {
365 &self.metadata
366 }
367
368 #[inline]
370 pub fn metadata_mut(&mut self) -> &mut Metadata {
371 &mut self.metadata
372 }
373
374 #[inline]
376 pub const fn name(&self) -> &String {
377 &self.name
378 }
379
380 #[inline]
382 pub fn set_name(&mut self, name: impl Into<String>) {
383 self.name = name.into();
384 }
385
386 pub fn with_name(mut self, name: impl Into<String>) -> Self {
396 self.set_name(name);
397 self
398 }
399
400 #[inline]
402 pub const fn data_type(&self) -> &DataType {
403 &self.data_type
404 }
405
406 #[inline]
416 pub fn set_data_type(&mut self, data_type: DataType) {
417 self.data_type = data_type;
418 }
419
420 pub fn with_data_type(mut self, data_type: DataType) -> Self {
430 self.set_data_type(data_type);
431 self
432 }
433
434 pub fn extension_type_name(&self) -> Option<&str> {
453 self.metadata()
454 .get(EXTENSION_TYPE_NAME_KEY)
455 .map(String::as_ref)
456 }
457
458 pub fn extension_type_metadata(&self) -> Option<&str> {
477 self.metadata()
478 .get(EXTENSION_TYPE_METADATA_KEY)
479 .map(String::as_ref)
480 }
481
482 #[inline]
491 pub fn has_valid_extension_type<E: ExtensionType>(&self) -> bool {
492 if self.extension_type_name() != Some(E::NAME) {
493 return false;
494 }
495
496 let ext_metadata = self
497 .metadata()
498 .get(EXTENSION_TYPE_METADATA_KEY)
499 .map(|s| s.as_str());
500
501 E::deserialize_metadata(ext_metadata)
502 .and_then(|metadata| E::validate(self.data_type(), metadata))
503 .is_ok()
504 }
505
506 pub fn try_extension_type<E: ExtensionType>(&self) -> Result<E, ArrowError> {
551 E::try_new_from_field_metadata(self.data_type(), self.metadata())
552 }
553
554 pub fn extension_type<E: ExtensionType>(&self) -> E {
562 self.try_extension_type::<E>()
563 .unwrap_or_else(|e| panic!("{e}"))
564 }
565
566 pub fn try_with_extension_type<E: ExtensionType>(
579 &mut self,
580 extension_type: E,
581 ) -> Result<(), ArrowError> {
582 extension_type.supports_data_type(&self.data_type)?;
584
585 self.metadata
586 .insert(EXTENSION_TYPE_NAME_KEY.to_owned(), E::NAME.to_owned());
587 match extension_type.serialize_metadata() {
588 Some(metadata) => self
589 .metadata
590 .insert(EXTENSION_TYPE_METADATA_KEY.to_owned(), metadata),
591 None => self.metadata.remove(EXTENSION_TYPE_METADATA_KEY),
594 };
595
596 Ok(())
597 }
598
599 pub fn with_extension_type<E: ExtensionType>(mut self, extension_type: E) -> Self {
607 self.try_with_extension_type(extension_type)
608 .unwrap_or_else(|e| panic!("{e}"));
609 self
610 }
611
612 #[cfg(feature = "canonical_extension_types")]
621 pub fn try_canonical_extension_type(&self) -> Result<CanonicalExtensionType, ArrowError> {
622 CanonicalExtensionType::try_from(self)
623 }
624
625 #[inline]
629 pub const fn is_nullable(&self) -> bool {
630 self.nullable
631 }
632
633 #[inline]
643 pub fn set_nullable(&mut self, nullable: bool) {
644 self.nullable = nullable;
645 }
646
647 pub fn with_nullable(mut self, nullable: bool) -> Self {
657 self.set_nullable(nullable);
658 self
659 }
660
661 pub(crate) fn fields(&self) -> Vec<&Field> {
664 let mut collected_fields = vec![self];
665 collected_fields.append(&mut Field::_fields(&self.data_type));
666
667 collected_fields
668 }
669
670 fn _fields(dt: &DataType) -> Vec<&Field> {
671 match dt {
672 DataType::Struct(fields) => fields.iter().flat_map(|f| f.fields()).collect(),
673 DataType::Union(fields, _) => fields.iter().flat_map(|(_, f)| f.fields()).collect(),
674 DataType::List(field)
675 | DataType::LargeList(field)
676 | DataType::ListView(field)
677 | DataType::LargeListView(field)
678 | DataType::FixedSizeList(field, _)
679 | DataType::Map(field, _) => field.fields(),
680 DataType::Dictionary(_, value_field) => Field::_fields(value_field.as_ref()),
681 DataType::RunEndEncoded(_, field) => field.fields(),
682 _ => vec![],
683 }
684 }
685
686 #[inline]
689 #[deprecated(
690 since = "54.0.0",
691 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
692 )]
693 pub(crate) fn fields_with_dict_id(&self, id: i64) -> Vec<&Field> {
694 self.fields()
695 .into_iter()
696 .filter(|&field| {
697 #[allow(deprecated)]
698 let matching_dict_id = field.dict_id == id;
699 matches!(field.data_type(), DataType::Dictionary(_, _)) && matching_dict_id
700 })
701 .collect()
702 }
703
704 #[inline]
706 #[deprecated(
707 since = "54.0.0",
708 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
709 )]
710 pub const fn dict_id(&self) -> Option<i64> {
711 match self.data_type {
712 #[allow(deprecated)]
713 DataType::Dictionary(_, _) => Some(self.dict_id),
714 _ => None,
715 }
716 }
717
718 #[inline]
733 pub const fn dict_is_ordered(&self) -> Option<bool> {
734 match self.data_type {
735 DataType::Dictionary(_, _) => Some(self.dict_is_ordered),
736 _ => None,
737 }
738 }
739
740 pub fn with_dict_is_ordered(mut self, dict_is_ordered: bool) -> Self {
746 if matches!(self.data_type, DataType::Dictionary(_, _)) {
747 self.dict_is_ordered = dict_is_ordered;
748 };
749 self
750 }
751
752 pub fn try_merge(&mut self, from: &Field) -> Result<(), ArrowError> {
767 if from.dict_is_ordered != self.dict_is_ordered {
768 return Err(ArrowError::SchemaError(format!(
769 "Fail to merge schema field '{}' because from dict_is_ordered = {} does not match {}",
770 self.name, from.dict_is_ordered, self.dict_is_ordered
771 )));
772 }
773 match (self.metadata().is_empty(), from.metadata().is_empty()) {
775 (false, false) => {
776 let mut merged = self.metadata().clone();
777 for (key, from_value) in from.metadata() {
778 if let Some(self_value) = self.metadata.get(key) {
779 if self_value != from_value {
780 return Err(ArrowError::SchemaError(format!(
781 "Fail to merge field '{}' due to conflicting metadata data value for key {}.
782 From value = {} does not match {}", self.name, key, from_value, self_value),
783 ));
784 }
785 } else {
786 merged.insert(key.clone(), from_value.clone());
787 }
788 }
789 self.set_metadata(merged);
790 }
791 (true, false) => {
792 self.set_metadata(from.metadata().clone());
793 }
794 _ => {}
795 }
796 match &mut self.data_type {
797 DataType::Struct(nested_fields) => match &from.data_type {
798 DataType::Struct(from_nested_fields) => {
799 let mut builder = SchemaBuilder::new();
800 nested_fields
801 .iter()
802 .chain(from_nested_fields)
803 .try_for_each(|f| builder.try_merge(f))?;
804 *nested_fields = builder.finish().fields;
805 }
806 DataType::Null => {
807 self.nullable = true;
808 }
809 _ => {
810 return Err(ArrowError::SchemaError(format!(
811 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Struct",
812 self.name, from.data_type
813 )));
814 }
815 },
816 DataType::Union(nested_fields, _) => match &from.data_type {
817 DataType::Union(from_nested_fields, _) => {
818 nested_fields.try_merge(from_nested_fields)?
819 }
820 DataType::Null => {
821 self.nullable = true;
822 }
823 _ => {
824 return Err(ArrowError::SchemaError(format!(
825 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Union",
826 self.name, from.data_type
827 )));
828 }
829 },
830 DataType::List(field) => match &from.data_type {
831 DataType::List(from_field) => {
832 let mut f = (**field).clone();
833 f.try_merge(from_field)?;
834 (*field) = Arc::new(f);
835 }
836 DataType::Null => {
837 self.nullable = true;
838 }
839 _ => {
840 return Err(ArrowError::SchemaError(format!(
841 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::List",
842 self.name, from.data_type
843 )));
844 }
845 },
846 DataType::LargeList(field) => match &from.data_type {
847 DataType::LargeList(from_field) => {
848 let mut f = (**field).clone();
849 f.try_merge(from_field)?;
850 (*field) = Arc::new(f);
851 }
852 DataType::Null => {
853 self.nullable = true;
854 }
855 _ => {
856 return Err(ArrowError::SchemaError(format!(
857 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::LargeList",
858 self.name, from.data_type
859 )));
860 }
861 },
862 DataType::Null => {
863 self.nullable = true;
864 self.data_type = from.data_type.clone();
865 }
866 DataType::Boolean
867 | DataType::Int8
868 | DataType::Int16
869 | DataType::Int32
870 | DataType::Int64
871 | DataType::UInt8
872 | DataType::UInt16
873 | DataType::UInt32
874 | DataType::UInt64
875 | DataType::Float16
876 | DataType::Float32
877 | DataType::Float64
878 | DataType::Timestamp(_, _)
879 | DataType::Date32
880 | DataType::Date64
881 | DataType::Time32(_)
882 | DataType::Time64(_)
883 | DataType::Duration(_)
884 | DataType::Binary
885 | DataType::LargeBinary
886 | DataType::BinaryView
887 | DataType::Interval(_)
888 | DataType::LargeListView(_)
889 | DataType::ListView(_)
890 | DataType::Map(_, _)
891 | DataType::Dictionary(_, _)
892 | DataType::RunEndEncoded(_, _)
893 | DataType::FixedSizeList(_, _)
894 | DataType::FixedSizeBinary(_)
895 | DataType::Utf8
896 | DataType::LargeUtf8
897 | DataType::Utf8View
898 | DataType::Decimal32(_, _)
899 | DataType::Decimal64(_, _)
900 | DataType::Decimal128(_, _)
901 | DataType::Decimal256(_, _) => {
902 if from.data_type == DataType::Null {
903 self.nullable = true;
904 } else if self.data_type != from.data_type {
905 return Err(ArrowError::SchemaError(format!(
906 "Fail to merge schema field '{}' because the from data_type = {} does not equal {}",
907 self.name, from.data_type, self.data_type
908 )));
909 }
910 }
911 }
912 self.nullable |= from.nullable;
913
914 Ok(())
915 }
916
917 pub fn contains(&self, other: &Field) -> bool {
923 self.name == other.name
924 && self.data_type.contains(&other.data_type)
925 && self.dict_is_ordered == other.dict_is_ordered
926 && (self.nullable || !other.nullable)
928 && other.metadata.iter().all(|(k, v1)| {
930 self.metadata.get(k).map(|v2| v1 == v2).unwrap_or_default()
931 })
932 }
933
934 pub fn size(&self) -> usize {
938 std::mem::size_of_val(self) - std::mem::size_of_val(&self.data_type)
939 + self.data_type.size()
940 + self.name.capacity()
941 + (std::mem::size_of::<(String, String)>() * self.metadata.len())
942 + self
943 .metadata
944 .iter()
945 .map(|(k, v)| k.capacity() + v.capacity())
946 .sum::<usize>()
947 }
948}
949
950impl std::fmt::Display for Field {
951 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
952 #![expect(deprecated)] let Self {
954 name,
955 data_type,
956 nullable,
957 dict_id,
958 dict_is_ordered,
959 metadata,
960 } = self;
961 let maybe_nullable = if *nullable { "nullable " } else { "" };
962 let metadata_str = if metadata.is_empty() {
963 String::new()
964 } else {
965 format!(", metadata: {metadata:?}")
966 };
967 let dict_id_str = if dict_id == &0 {
968 String::new()
969 } else {
970 format!(", dict_id: {dict_id}")
971 };
972 let dict_is_ordered_str = if *dict_is_ordered {
973 ", dict_is_ordered"
974 } else {
975 ""
976 };
977 write!(
978 f,
979 "Field {{ {name:?}: {maybe_nullable}{data_type}{dict_id_str}{dict_is_ordered_str}{metadata_str} }}"
980 )
981 }
982}
983
984#[cfg(test)]
985mod test {
986 use super::*;
987 use std::collections::HashMap;
988 use std::collections::hash_map::DefaultHasher;
989
990 #[derive(Debug, Clone, Copy)]
991 struct TestExtensionType;
992
993 impl ExtensionType for TestExtensionType {
994 const NAME: &'static str = "test.extension";
995 type Metadata = ();
996
997 fn metadata(&self) -> &Self::Metadata {
998 &()
999 }
1000
1001 fn serialize_metadata(&self) -> Option<String> {
1002 None
1003 }
1004
1005 fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
1006 metadata.map_or(Ok(()), |_| {
1007 Err(ArrowError::InvalidArgumentError(
1008 "TestExtensionType expects no metadata".to_owned(),
1009 ))
1010 })
1011 }
1012
1013 fn supports_data_type(&self, _data_type: &DataType) -> Result<(), ArrowError> {
1014 Ok(())
1015 }
1016
1017 fn try_new(_data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
1018 Ok(Self)
1019 }
1020 }
1021
1022 #[test]
1023 fn test_has_valid_extension_type() {
1024 let no_extension = Field::new("f", DataType::Null, false);
1025 assert!(!no_extension.has_valid_extension_type::<TestExtensionType>());
1026
1027 let matching_name = Field::new("f", DataType::Null, false)
1028 .with_metadata([(EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME)]);
1029 assert!(matching_name.has_valid_extension_type::<TestExtensionType>());
1030
1031 let matching_name_with_invalid_metadata = Field::new("f", DataType::Null, false)
1032 .with_metadata([
1033 (EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME),
1034 (EXTENSION_TYPE_METADATA_KEY, "invalid"),
1035 ]);
1036 assert!(
1037 !matching_name_with_invalid_metadata.has_valid_extension_type::<TestExtensionType>()
1038 );
1039
1040 let different_name = Field::new("f", DataType::Null, false)
1041 .with_metadata([(EXTENSION_TYPE_NAME_KEY, "some.other_extension")]);
1042 assert!(!different_name.has_valid_extension_type::<TestExtensionType>());
1043 }
1044
1045 #[test]
1046 fn test_new_with_string() {
1047 let s = "c1";
1049 Field::new(s, DataType::Int64, false);
1050 }
1051
1052 #[test]
1053 fn test_new_dict_with_string() {
1054 let s = "c1";
1056 #[allow(deprecated)]
1057 Field::new_dict(s, DataType::Int64, false, 4, false);
1058 }
1059
1060 #[test]
1061 #[cfg_attr(miri, ignore)] fn test_debug_format_field() {
1063 insta::assert_debug_snapshot!(Field::new("item", DataType::UInt8, false), @r"
1065 Field {
1066 data_type: UInt8,
1067 }
1068 ");
1069 insta::assert_debug_snapshot!(Field::new("column", DataType::LargeUtf8, true), @r#"
1070 Field {
1071 name: "column",
1072 data_type: LargeUtf8,
1073 nullable: true,
1074 }
1075 "#);
1076 }
1077
1078 #[test]
1079 fn test_merge_incompatible_types() {
1080 let mut field = Field::new("c1", DataType::Int64, false);
1081 let result = field
1082 .try_merge(&Field::new("c1", DataType::Float32, true))
1083 .expect_err("should fail")
1084 .to_string();
1085 assert_eq!(
1086 "Schema error: Fail to merge schema field 'c1' because the from data_type = Float32 does not equal Int64",
1087 result
1088 );
1089 }
1090
1091 #[test]
1092 fn test_merge_with_null() {
1093 let mut field1 = Field::new("c1", DataType::Null, true);
1094 field1
1095 .try_merge(&Field::new("c1", DataType::Float32, false))
1096 .expect("should widen type to nullable float");
1097 assert_eq!(Field::new("c1", DataType::Float32, true), field1);
1098
1099 let mut field2 = Field::new("c2", DataType::Utf8, false);
1100 field2
1101 .try_merge(&Field::new("c2", DataType::Null, true))
1102 .expect("should widen type to nullable utf8");
1103 assert_eq!(Field::new("c2", DataType::Utf8, true), field2);
1104 }
1105
1106 #[test]
1107 fn test_merge_with_nested_null() {
1108 let mut struct1 = Field::new(
1109 "s1",
1110 DataType::Struct(Fields::from(vec![Field::new(
1111 "inner",
1112 DataType::Float32,
1113 false,
1114 )])),
1115 false,
1116 );
1117
1118 let struct2 = Field::new(
1119 "s2",
1120 DataType::Struct(Fields::from(vec![Field::new(
1121 "inner",
1122 DataType::Null,
1123 false,
1124 )])),
1125 true,
1126 );
1127
1128 struct1
1129 .try_merge(&struct2)
1130 .expect("should widen inner field's type to nullable float");
1131 assert_eq!(
1132 Field::new(
1133 "s1",
1134 DataType::Struct(Fields::from(vec![Field::new(
1135 "inner",
1136 DataType::Float32,
1137 true,
1138 )])),
1139 true,
1140 ),
1141 struct1
1142 );
1143
1144 let mut list1 = Field::new(
1145 "l1",
1146 DataType::List(Field::new("inner", DataType::Float32, false).into()),
1147 false,
1148 );
1149
1150 let list2 = Field::new(
1151 "l2",
1152 DataType::List(Field::new("inner", DataType::Null, false).into()),
1153 true,
1154 );
1155
1156 list1
1157 .try_merge(&list2)
1158 .expect("should widen inner field's type to nullable float");
1159 assert_eq!(
1160 Field::new(
1161 "l1",
1162 DataType::List(Field::new("inner", DataType::Float32, true).into()),
1163 true,
1164 ),
1165 list1
1166 );
1167
1168 let mut large_list1 = Field::new(
1169 "ll1",
1170 DataType::LargeList(Field::new("inner", DataType::Float32, false).into()),
1171 false,
1172 );
1173
1174 let large_list2 = Field::new(
1175 "ll2",
1176 DataType::LargeList(Field::new("inner", DataType::Null, false).into()),
1177 true,
1178 );
1179
1180 large_list1
1181 .try_merge(&large_list2)
1182 .expect("should widen inner field's type to nullable float");
1183 assert_eq!(
1184 Field::new(
1185 "ll1",
1186 DataType::LargeList(Field::new("inner", DataType::Float32, true).into()),
1187 true,
1188 ),
1189 large_list1
1190 );
1191 }
1192
1193 #[test]
1194 fn test_fields_with_dict_id() {
1195 #[allow(deprecated)]
1196 let dict1 = Field::new_dict(
1197 "dict1",
1198 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1199 false,
1200 10,
1201 false,
1202 );
1203 #[allow(deprecated)]
1204 let dict2 = Field::new_dict(
1205 "dict2",
1206 DataType::Dictionary(DataType::Int32.into(), DataType::Int8.into()),
1207 false,
1208 20,
1209 false,
1210 );
1211
1212 let field = Field::new(
1213 "struct<dict1, list[struct<dict2, list[struct<dict1]>]>",
1214 DataType::Struct(Fields::from(vec![
1215 dict1.clone(),
1216 Field::new(
1217 "list[struct<dict1, list[struct<dict2>]>]",
1218 DataType::List(Arc::new(Field::new(
1219 "struct<dict1, list[struct<dict2>]>",
1220 DataType::Struct(Fields::from(vec![
1221 dict1.clone(),
1222 Field::new(
1223 "list[struct<dict2>]",
1224 DataType::List(Arc::new(Field::new(
1225 "struct<dict2>",
1226 DataType::Struct(vec![dict2.clone()].into()),
1227 false,
1228 ))),
1229 false,
1230 ),
1231 ])),
1232 false,
1233 ))),
1234 false,
1235 ),
1236 ])),
1237 false,
1238 );
1239
1240 #[allow(deprecated)]
1241 for field in field.fields_with_dict_id(10) {
1242 assert_eq!(dict1, *field);
1243 }
1244 #[allow(deprecated)]
1245 for field in field.fields_with_dict_id(20) {
1246 assert_eq!(dict2, *field);
1247 }
1248 }
1249
1250 fn get_field_hash(field: &Field) -> u64 {
1251 let mut s = DefaultHasher::new();
1252 field.hash(&mut s);
1253 s.finish()
1254 }
1255
1256 #[test]
1257 fn test_field_comparison_case() {
1258 #[allow(deprecated)]
1260 let dict1 = Field::new_dict(
1261 "dict1",
1262 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1263 false,
1264 10,
1265 false,
1266 );
1267 #[allow(deprecated)]
1268 let dict2 = Field::new_dict(
1269 "dict1",
1270 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1271 false,
1272 20,
1273 false,
1274 );
1275
1276 assert_eq!(dict1, dict2);
1277 assert_eq!(get_field_hash(&dict1), get_field_hash(&dict2));
1278
1279 #[allow(deprecated)]
1280 let dict1 = Field::new_dict(
1281 "dict0",
1282 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1283 false,
1284 10,
1285 false,
1286 );
1287
1288 assert_ne!(dict1, dict2);
1289 assert_ne!(get_field_hash(&dict1), get_field_hash(&dict2));
1290 }
1291
1292 #[test]
1293 fn test_field_comparison_metadata() {
1294 let f1 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1295 (String::from("k1"), String::from("v1")),
1296 (String::from("k2"), String::from("v2")),
1297 ]));
1298 let f2 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1299 (String::from("k1"), String::from("v1")),
1300 (String::from("k3"), String::from("v3")),
1301 ]));
1302 let f3 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1303 (String::from("k1"), String::from("v1")),
1304 (String::from("k3"), String::from("v4")),
1305 ]));
1306
1307 assert!(f1.cmp(&f2).is_lt());
1308 assert!(f2.cmp(&f3).is_lt());
1309 assert!(f1.cmp(&f3).is_lt());
1310 }
1311
1312 #[test]
1313 #[expect(clippy::needless_borrows_for_generic_args)] fn test_field_as_ref() {
1315 let field = || Field::new("x", DataType::Binary, false);
1316
1317 fn accept_ref(_: impl AsRef<Field>) {}
1320
1321 accept_ref(field());
1322 accept_ref(&field());
1323 accept_ref(&&field());
1324 accept_ref(Arc::new(field()));
1325 accept_ref(&Arc::new(field()));
1326 accept_ref(&&Arc::new(field()));
1327
1328 fn accept_refs(_: impl IntoIterator<Item: AsRef<Field>>) {}
1331
1332 accept_refs(vec![field()]);
1333 accept_refs(vec![&field()]);
1334 accept_refs(vec![Arc::new(field())]);
1335 accept_refs(vec![&Arc::new(field())]);
1336 accept_refs(&vec![field()]);
1337 accept_refs(&vec![&field()]);
1338 accept_refs(&vec![Arc::new(field())]);
1339 accept_refs(&vec![&Arc::new(field())]);
1340 }
1341
1342 #[test]
1343 fn test_contains_reflexivity() {
1344 let mut field = Field::new("field1", DataType::Float16, false);
1345 field.set_metadata(HashMap::from([
1346 (String::from("k0"), String::from("v0")),
1347 (String::from("k1"), String::from("v1")),
1348 ]));
1349 assert!(field.contains(&field))
1350 }
1351
1352 #[test]
1353 fn test_contains_transitivity() {
1354 let child_field = Field::new("child1", DataType::Float16, false);
1355
1356 let mut field1 = Field::new(
1357 "field1",
1358 DataType::Struct(Fields::from(vec![child_field])),
1359 false,
1360 );
1361 field1.set_metadata(HashMap::from([(String::from("k1"), String::from("v1"))]));
1362
1363 let mut field2 = Field::new("field1", DataType::Struct(Fields::default()), true);
1364 field2.set_metadata(HashMap::from([(String::from("k2"), String::from("v2"))]));
1365 field2.try_merge(&field1).unwrap();
1366
1367 let mut field3 = Field::new("field1", DataType::Struct(Fields::default()), false);
1368 field3.set_metadata(HashMap::from([(String::from("k3"), String::from("v3"))]));
1369 field3.try_merge(&field2).unwrap();
1370
1371 assert!(field2.contains(&field1));
1372 assert!(field3.contains(&field2));
1373 assert!(field3.contains(&field1));
1374
1375 assert!(!field1.contains(&field2));
1376 assert!(!field1.contains(&field3));
1377 assert!(!field2.contains(&field3));
1378 }
1379
1380 #[test]
1381 fn test_contains_nullable() {
1382 let field1 = Field::new("field1", DataType::Boolean, true);
1383 let field2 = Field::new("field1", DataType::Boolean, false);
1384 assert!(field1.contains(&field2));
1385 assert!(!field2.contains(&field1));
1386 }
1387
1388 #[test]
1389 fn test_contains_must_have_same_fields() {
1390 let child_field1 = Field::new("child1", DataType::Float16, false);
1391 let child_field2 = Field::new("child2", DataType::Float16, false);
1392
1393 let field1 = Field::new(
1394 "field1",
1395 DataType::Struct(vec![child_field1.clone()].into()),
1396 true,
1397 );
1398 let field2 = Field::new(
1399 "field1",
1400 DataType::Struct(vec![child_field1, child_field2].into()),
1401 true,
1402 );
1403
1404 assert!(!field1.contains(&field2));
1405 assert!(!field2.contains(&field1));
1406
1407 let field1 = Field::new(
1409 "field1",
1410 DataType::Union(
1411 UnionFields::try_new(
1412 vec![1, 2],
1413 vec![
1414 Field::new("field1", DataType::UInt8, true),
1415 Field::new("field3", DataType::Utf8, false),
1416 ],
1417 )
1418 .unwrap(),
1419 UnionMode::Dense,
1420 ),
1421 true,
1422 );
1423 let field2 = Field::new(
1424 "field1",
1425 DataType::Union(
1426 UnionFields::try_new(
1427 vec![1, 3],
1428 vec![
1429 Field::new("field1", DataType::UInt8, false),
1430 Field::new("field3", DataType::Utf8, false),
1431 ],
1432 )
1433 .unwrap(),
1434 UnionMode::Dense,
1435 ),
1436 true,
1437 );
1438 assert!(!field1.contains(&field2));
1439
1440 let field1 = Field::new(
1442 "field1",
1443 DataType::Union(
1444 UnionFields::try_new(
1445 vec![1, 2],
1446 vec![
1447 Field::new("field1", DataType::UInt8, true),
1448 Field::new("field3", DataType::Utf8, false),
1449 ],
1450 )
1451 .unwrap(),
1452 UnionMode::Dense,
1453 ),
1454 true,
1455 );
1456 let field2 = Field::new(
1457 "field1",
1458 DataType::Union(
1459 UnionFields::try_new(
1460 vec![1, 2],
1461 vec![
1462 Field::new("field1", DataType::UInt8, false),
1463 Field::new("field3", DataType::Utf8, false),
1464 ],
1465 )
1466 .unwrap(),
1467 UnionMode::Dense,
1468 ),
1469 true,
1470 );
1471 assert!(field1.contains(&field2));
1472 }
1473
1474 #[cfg(feature = "serde")]
1475 fn assert_binary_serde_round_trip(field: Field) {
1476 let serialized = postcard::to_stdvec(&field).unwrap();
1477 let deserialized: Field = postcard::from_bytes(&serialized).unwrap();
1478 assert_eq!(field, deserialized)
1479 }
1480
1481 #[cfg(feature = "serde")]
1482 #[test]
1483 fn test_field_without_metadata_serde() {
1484 let field = Field::new("name", DataType::Boolean, true);
1485 assert_binary_serde_round_trip(field)
1486 }
1487
1488 #[cfg(feature = "serde")]
1489 #[test]
1490 fn test_field_with_empty_metadata_serde() {
1491 let field = Field::new("name", DataType::Boolean, false).with_metadata(HashMap::new());
1492
1493 assert_binary_serde_round_trip(field)
1494 }
1495
1496 #[cfg(feature = "serde")]
1497 #[test]
1498 fn test_field_with_nonempty_metadata_serde() {
1499 let mut metadata = HashMap::new();
1500 metadata.insert("hi".to_owned(), "".to_owned());
1501 let field = Field::new("name", DataType::Boolean, false).with_metadata(metadata);
1502
1503 assert_binary_serde_round_trip(field)
1504 }
1505
1506 #[test]
1507 fn test_merge_compound_with_null() {
1508 let mut field = Field::new(
1510 "s",
1511 DataType::Struct(Fields::from(vec![Field::new("a", DataType::Int32, false)])),
1512 false,
1513 );
1514 field
1515 .try_merge(&Field::new("s", DataType::Null, true))
1516 .expect("Struct should merge with Null");
1517 assert!(field.is_nullable());
1518 assert!(matches!(field.data_type(), DataType::Struct(_)));
1519
1520 let mut field = Field::new(
1522 "l",
1523 DataType::List(Field::new("item", DataType::Utf8, false).into()),
1524 false,
1525 );
1526 field
1527 .try_merge(&Field::new("l", DataType::Null, true))
1528 .expect("List should merge with Null");
1529 assert!(field.is_nullable());
1530 assert!(matches!(field.data_type(), DataType::List(_)));
1531
1532 let mut field = Field::new(
1534 "ll",
1535 DataType::LargeList(Field::new("item", DataType::Utf8, false).into()),
1536 false,
1537 );
1538 field
1539 .try_merge(&Field::new("ll", DataType::Null, true))
1540 .expect("LargeList should merge with Null");
1541 assert!(field.is_nullable());
1542 assert!(matches!(field.data_type(), DataType::LargeList(_)));
1543
1544 let mut field = Field::new(
1546 "u",
1547 DataType::Union(
1548 UnionFields::try_new(vec![0], vec![Field::new("f", DataType::Int32, false)])
1549 .unwrap(),
1550 UnionMode::Dense,
1551 ),
1552 false,
1553 );
1554 field
1555 .try_merge(&Field::new("u", DataType::Null, true))
1556 .expect("Union should merge with Null");
1557 assert!(matches!(field.data_type(), DataType::Union(_, _)));
1558 }
1559}