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
154 pub fn new(name: impl Into<String>, data_type: DataType, nullable: bool) -> Self {
162 #[allow(deprecated)]
163 Field {
164 name: name.into(),
165 data_type,
166 nullable,
167 dict_id: 0,
168 dict_is_ordered: false,
169 metadata: Default::default(),
170 }
171 }
172
173 pub fn new_list_field(data_type: DataType, nullable: bool) -> Self {
188 Self::new(Self::LIST_FIELD_DEFAULT_NAME, data_type, nullable)
189 }
190
191 #[deprecated(
193 since = "54.0.0",
194 note = "The ability to preserve dictionary IDs will be removed. With the dict_id field disappearing this function signature will change by removing the dict_id parameter."
195 )]
196 pub fn new_dict(
197 name: impl Into<String>,
198 data_type: DataType,
199 nullable: bool,
200 dict_id: i64,
201 dict_is_ordered: bool,
202 ) -> Self {
203 #[allow(deprecated)]
204 Field {
205 name: name.into(),
206 data_type,
207 nullable,
208 dict_id,
209 dict_is_ordered,
210 metadata: Default::default(),
211 }
212 }
213
214 pub fn new_dictionary(
222 name: impl Into<String>,
223 key: DataType,
224 value: DataType,
225 nullable: bool,
226 ) -> Self {
227 assert!(
228 key.is_dictionary_key_type(),
229 "{key} is not a valid dictionary key"
230 );
231 let data_type = DataType::Dictionary(Box::new(key), Box::new(value));
232 Self::new(name, data_type, nullable)
233 }
234
235 pub fn new_struct(name: impl Into<String>, fields: impl Into<Fields>, nullable: bool) -> Self {
241 Self::new(name, DataType::Struct(fields.into()), nullable)
242 }
243
244 pub fn new_list(name: impl Into<String>, value: impl Into<FieldRef>, nullable: bool) -> Self {
250 Self::new(name, DataType::List(value.into()), nullable)
251 }
252
253 pub fn new_large_list(
259 name: impl Into<String>,
260 value: impl Into<FieldRef>,
261 nullable: bool,
262 ) -> Self {
263 Self::new(name, DataType::LargeList(value.into()), nullable)
264 }
265
266 pub fn new_fixed_size_list(
273 name: impl Into<String>,
274 value: impl Into<FieldRef>,
275 size: i32,
276 nullable: bool,
277 ) -> Self {
278 Self::new(name, DataType::FixedSizeList(value.into(), size), nullable)
279 }
280
281 pub fn new_map(
290 name: impl Into<String>,
291 entries: impl Into<String>,
292 keys: impl Into<FieldRef>,
293 values: impl Into<FieldRef>,
294 sorted: bool,
295 nullable: bool,
296 ) -> Self {
297 let data_type = DataType::Map(
298 Arc::new(Field::new(
299 entries.into(),
300 DataType::Struct(Fields::from([keys.into(), values.into()])),
301 false, )),
303 sorted,
304 );
305 Self::new(name, data_type, nullable)
306 }
307
308 pub fn new_union<S, F, T>(name: S, type_ids: T, fields: F, mode: UnionMode) -> Self
322 where
323 S: Into<String>,
324 F: IntoIterator,
325 F::Item: Into<FieldRef>,
326 T: IntoIterator<Item = i8>,
327 {
328 Self::new(
329 name,
330 DataType::Union(
331 UnionFields::try_new(type_ids, fields).expect("Invalid UnionField"),
332 mode,
333 ),
334 false, )
336 }
337
338 #[inline]
340 pub fn set_metadata(&mut self, metadata: impl Into<Metadata>) {
341 self.metadata = metadata.into();
342 }
343
344 pub fn with_metadata(mut self, metadata: impl Into<Metadata>) -> Self {
346 self.set_metadata(metadata);
347 self
348 }
349
350 #[inline]
352 pub const fn metadata(&self) -> &Metadata {
353 &self.metadata
354 }
355
356 #[inline]
358 pub fn metadata_mut(&mut self) -> &mut Metadata {
359 &mut self.metadata
360 }
361
362 #[inline]
364 pub const fn name(&self) -> &String {
365 &self.name
366 }
367
368 #[inline]
370 pub fn set_name(&mut self, name: impl Into<String>) {
371 self.name = name.into();
372 }
373
374 pub fn with_name(mut self, name: impl Into<String>) -> Self {
384 self.set_name(name);
385 self
386 }
387
388 #[inline]
390 pub const fn data_type(&self) -> &DataType {
391 &self.data_type
392 }
393
394 #[inline]
404 pub fn set_data_type(&mut self, data_type: DataType) {
405 self.data_type = data_type;
406 }
407
408 pub fn with_data_type(mut self, data_type: DataType) -> Self {
418 self.set_data_type(data_type);
419 self
420 }
421
422 pub fn extension_type_name(&self) -> Option<&str> {
441 self.metadata()
442 .get(EXTENSION_TYPE_NAME_KEY)
443 .map(String::as_ref)
444 }
445
446 pub fn extension_type_metadata(&self) -> Option<&str> {
465 self.metadata()
466 .get(EXTENSION_TYPE_METADATA_KEY)
467 .map(String::as_ref)
468 }
469
470 #[inline]
479 pub fn has_valid_extension_type<E: ExtensionType>(&self) -> bool {
480 if self.extension_type_name() != Some(E::NAME) {
481 return false;
482 }
483
484 let ext_metadata = self
485 .metadata()
486 .get(EXTENSION_TYPE_METADATA_KEY)
487 .map(|s| s.as_str());
488
489 E::deserialize_metadata(ext_metadata)
490 .and_then(|metadata| E::validate(self.data_type(), metadata))
491 .is_ok()
492 }
493
494 pub fn try_extension_type<E: ExtensionType>(&self) -> Result<E, ArrowError> {
539 E::try_new_from_field_metadata(self.data_type(), self.metadata())
540 }
541
542 pub fn extension_type<E: ExtensionType>(&self) -> E {
550 self.try_extension_type::<E>()
551 .unwrap_or_else(|e| panic!("{e}"))
552 }
553
554 pub fn try_with_extension_type<E: ExtensionType>(
567 &mut self,
568 extension_type: E,
569 ) -> Result<(), ArrowError> {
570 extension_type.supports_data_type(&self.data_type)?;
572
573 self.metadata
574 .insert(EXTENSION_TYPE_NAME_KEY.to_owned(), E::NAME.to_owned());
575 match extension_type.serialize_metadata() {
576 Some(metadata) => self
577 .metadata
578 .insert(EXTENSION_TYPE_METADATA_KEY.to_owned(), metadata),
579 None => self.metadata.remove(EXTENSION_TYPE_METADATA_KEY),
582 };
583
584 Ok(())
585 }
586
587 pub fn with_extension_type<E: ExtensionType>(mut self, extension_type: E) -> Self {
595 self.try_with_extension_type(extension_type)
596 .unwrap_or_else(|e| panic!("{e}"));
597 self
598 }
599
600 #[cfg(feature = "canonical_extension_types")]
609 pub fn try_canonical_extension_type(&self) -> Result<CanonicalExtensionType, ArrowError> {
610 CanonicalExtensionType::try_from(self)
611 }
612
613 #[inline]
617 pub const fn is_nullable(&self) -> bool {
618 self.nullable
619 }
620
621 #[inline]
631 pub fn set_nullable(&mut self, nullable: bool) {
632 self.nullable = nullable;
633 }
634
635 pub fn with_nullable(mut self, nullable: bool) -> Self {
645 self.set_nullable(nullable);
646 self
647 }
648
649 pub(crate) fn fields(&self) -> Vec<&Field> {
652 let mut collected_fields = vec![self];
653 collected_fields.append(&mut Field::_fields(&self.data_type));
654
655 collected_fields
656 }
657
658 fn _fields(dt: &DataType) -> Vec<&Field> {
659 match dt {
660 DataType::Struct(fields) => fields.iter().flat_map(|f| f.fields()).collect(),
661 DataType::Union(fields, _) => fields.iter().flat_map(|(_, f)| f.fields()).collect(),
662 DataType::List(field)
663 | DataType::LargeList(field)
664 | DataType::ListView(field)
665 | DataType::LargeListView(field)
666 | DataType::FixedSizeList(field, _)
667 | DataType::Map(field, _) => field.fields(),
668 DataType::Dictionary(_, value_field) => Field::_fields(value_field.as_ref()),
669 DataType::RunEndEncoded(_, field) => field.fields(),
670 _ => vec![],
671 }
672 }
673
674 #[inline]
677 #[deprecated(
678 since = "54.0.0",
679 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
680 )]
681 pub(crate) fn fields_with_dict_id(&self, id: i64) -> Vec<&Field> {
682 self.fields()
683 .into_iter()
684 .filter(|&field| {
685 #[allow(deprecated)]
686 let matching_dict_id = field.dict_id == id;
687 matches!(field.data_type(), DataType::Dictionary(_, _)) && matching_dict_id
688 })
689 .collect()
690 }
691
692 #[inline]
694 #[deprecated(
695 since = "54.0.0",
696 note = "The ability to preserve dictionary IDs will be removed. With it, all fields related to it."
697 )]
698 pub const fn dict_id(&self) -> Option<i64> {
699 match self.data_type {
700 #[allow(deprecated)]
701 DataType::Dictionary(_, _) => Some(self.dict_id),
702 _ => None,
703 }
704 }
705
706 #[inline]
721 pub const fn dict_is_ordered(&self) -> Option<bool> {
722 match self.data_type {
723 DataType::Dictionary(_, _) => Some(self.dict_is_ordered),
724 _ => None,
725 }
726 }
727
728 pub fn with_dict_is_ordered(mut self, dict_is_ordered: bool) -> Self {
734 if matches!(self.data_type, DataType::Dictionary(_, _)) {
735 self.dict_is_ordered = dict_is_ordered;
736 };
737 self
738 }
739
740 pub fn try_merge(&mut self, from: &Field) -> Result<(), ArrowError> {
755 if from.dict_is_ordered != self.dict_is_ordered {
756 return Err(ArrowError::SchemaError(format!(
757 "Fail to merge schema field '{}' because from dict_is_ordered = {} does not match {}",
758 self.name, from.dict_is_ordered, self.dict_is_ordered
759 )));
760 }
761 match (self.metadata().is_empty(), from.metadata().is_empty()) {
763 (false, false) => {
764 let mut merged = self.metadata().clone();
765 for (key, from_value) in from.metadata() {
766 if let Some(self_value) = self.metadata.get(key) {
767 if self_value != from_value {
768 return Err(ArrowError::SchemaError(format!(
769 "Fail to merge field '{}' due to conflicting metadata data value for key {}.
770 From value = {} does not match {}", self.name, key, from_value, self_value),
771 ));
772 }
773 } else {
774 merged.insert(key.clone(), from_value.clone());
775 }
776 }
777 self.set_metadata(merged);
778 }
779 (true, false) => {
780 self.set_metadata(from.metadata().clone());
781 }
782 _ => {}
783 }
784 match &mut self.data_type {
785 DataType::Struct(nested_fields) => match &from.data_type {
786 DataType::Struct(from_nested_fields) => {
787 let mut builder = SchemaBuilder::new();
788 nested_fields
789 .iter()
790 .chain(from_nested_fields)
791 .try_for_each(|f| builder.try_merge(f))?;
792 *nested_fields = builder.finish().fields;
793 }
794 DataType::Null => {
795 self.nullable = true;
796 }
797 _ => {
798 return Err(ArrowError::SchemaError(format!(
799 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Struct",
800 self.name, from.data_type
801 )));
802 }
803 },
804 DataType::Union(nested_fields, _) => match &from.data_type {
805 DataType::Union(from_nested_fields, _) => {
806 nested_fields.try_merge(from_nested_fields)?
807 }
808 DataType::Null => {
809 self.nullable = true;
810 }
811 _ => {
812 return Err(ArrowError::SchemaError(format!(
813 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::Union",
814 self.name, from.data_type
815 )));
816 }
817 },
818 DataType::List(field) => match &from.data_type {
819 DataType::List(from_field) => {
820 let mut f = (**field).clone();
821 f.try_merge(from_field)?;
822 (*field) = Arc::new(f);
823 }
824 DataType::Null => {
825 self.nullable = true;
826 }
827 _ => {
828 return Err(ArrowError::SchemaError(format!(
829 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::List",
830 self.name, from.data_type
831 )));
832 }
833 },
834 DataType::LargeList(field) => match &from.data_type {
835 DataType::LargeList(from_field) => {
836 let mut f = (**field).clone();
837 f.try_merge(from_field)?;
838 (*field) = Arc::new(f);
839 }
840 DataType::Null => {
841 self.nullable = true;
842 }
843 _ => {
844 return Err(ArrowError::SchemaError(format!(
845 "Fail to merge schema field '{}' because the from data_type = {} is not DataType::LargeList",
846 self.name, from.data_type
847 )));
848 }
849 },
850 DataType::Null => {
851 self.nullable = true;
852 self.data_type = from.data_type.clone();
853 }
854 DataType::Boolean
855 | DataType::Int8
856 | DataType::Int16
857 | DataType::Int32
858 | DataType::Int64
859 | DataType::UInt8
860 | DataType::UInt16
861 | DataType::UInt32
862 | DataType::UInt64
863 | DataType::Float16
864 | DataType::Float32
865 | DataType::Float64
866 | DataType::Timestamp(_, _)
867 | DataType::Date32
868 | DataType::Date64
869 | DataType::Time32(_)
870 | DataType::Time64(_)
871 | DataType::Duration(_)
872 | DataType::Binary
873 | DataType::LargeBinary
874 | DataType::BinaryView
875 | DataType::Interval(_)
876 | DataType::LargeListView(_)
877 | DataType::ListView(_)
878 | DataType::Map(_, _)
879 | DataType::Dictionary(_, _)
880 | DataType::RunEndEncoded(_, _)
881 | DataType::FixedSizeList(_, _)
882 | DataType::FixedSizeBinary(_)
883 | DataType::Utf8
884 | DataType::LargeUtf8
885 | DataType::Utf8View
886 | DataType::Decimal32(_, _)
887 | DataType::Decimal64(_, _)
888 | DataType::Decimal128(_, _)
889 | DataType::Decimal256(_, _) => {
890 if from.data_type == DataType::Null {
891 self.nullable = true;
892 } else if self.data_type != from.data_type {
893 return Err(ArrowError::SchemaError(format!(
894 "Fail to merge schema field '{}' because the from data_type = {} does not equal {}",
895 self.name, from.data_type, self.data_type
896 )));
897 }
898 }
899 }
900 self.nullable |= from.nullable;
901
902 Ok(())
903 }
904
905 pub fn contains(&self, other: &Field) -> bool {
911 self.name == other.name
912 && self.data_type.contains(&other.data_type)
913 && self.dict_is_ordered == other.dict_is_ordered
914 && (self.nullable || !other.nullable)
916 && other.metadata.iter().all(|(k, v1)| {
918 self.metadata.get(k).map(|v2| v1 == v2).unwrap_or_default()
919 })
920 }
921
922 pub fn size(&self) -> usize {
926 std::mem::size_of_val(self) - std::mem::size_of_val(&self.data_type)
927 + self.data_type.size()
928 + self.name.capacity()
929 + (std::mem::size_of::<(String, String)>() * self.metadata.len())
930 + self
931 .metadata
932 .iter()
933 .map(|(k, v)| k.capacity() + v.capacity())
934 .sum::<usize>()
935 }
936}
937
938impl std::fmt::Display for Field {
939 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
940 #![expect(deprecated)] let Self {
942 name,
943 data_type,
944 nullable,
945 dict_id,
946 dict_is_ordered,
947 metadata,
948 } = self;
949 let maybe_nullable = if *nullable { "nullable " } else { "" };
950 let metadata_str = if metadata.is_empty() {
951 String::new()
952 } else {
953 format!(", metadata: {metadata:?}")
954 };
955 let dict_id_str = if dict_id == &0 {
956 String::new()
957 } else {
958 format!(", dict_id: {dict_id}")
959 };
960 let dict_is_ordered_str = if *dict_is_ordered {
961 ", dict_is_ordered"
962 } else {
963 ""
964 };
965 write!(
966 f,
967 "Field {{ {name:?}: {maybe_nullable}{data_type}{dict_id_str}{dict_is_ordered_str}{metadata_str} }}"
968 )
969 }
970}
971
972#[cfg(test)]
973mod test {
974 use super::*;
975 use std::collections::HashMap;
976 use std::collections::hash_map::DefaultHasher;
977
978 #[derive(Debug, Clone, Copy)]
979 struct TestExtensionType;
980
981 impl ExtensionType for TestExtensionType {
982 const NAME: &'static str = "test.extension";
983 type Metadata = ();
984
985 fn metadata(&self) -> &Self::Metadata {
986 &()
987 }
988
989 fn serialize_metadata(&self) -> Option<String> {
990 None
991 }
992
993 fn deserialize_metadata(metadata: Option<&str>) -> Result<Self::Metadata, ArrowError> {
994 metadata.map_or(Ok(()), |_| {
995 Err(ArrowError::InvalidArgumentError(
996 "TestExtensionType expects no metadata".to_owned(),
997 ))
998 })
999 }
1000
1001 fn supports_data_type(&self, _data_type: &DataType) -> Result<(), ArrowError> {
1002 Ok(())
1003 }
1004
1005 fn try_new(_data_type: &DataType, _metadata: Self::Metadata) -> Result<Self, ArrowError> {
1006 Ok(Self)
1007 }
1008 }
1009
1010 #[test]
1011 fn test_has_valid_extension_type() {
1012 let no_extension = Field::new("f", DataType::Null, false);
1013 assert!(!no_extension.has_valid_extension_type::<TestExtensionType>());
1014
1015 let matching_name = Field::new("f", DataType::Null, false)
1016 .with_metadata([(EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME)]);
1017 assert!(matching_name.has_valid_extension_type::<TestExtensionType>());
1018
1019 let matching_name_with_invalid_metadata = Field::new("f", DataType::Null, false)
1020 .with_metadata([
1021 (EXTENSION_TYPE_NAME_KEY, TestExtensionType::NAME),
1022 (EXTENSION_TYPE_METADATA_KEY, "invalid"),
1023 ]);
1024 assert!(
1025 !matching_name_with_invalid_metadata.has_valid_extension_type::<TestExtensionType>()
1026 );
1027
1028 let different_name = Field::new("f", DataType::Null, false)
1029 .with_metadata([(EXTENSION_TYPE_NAME_KEY, "some.other_extension")]);
1030 assert!(!different_name.has_valid_extension_type::<TestExtensionType>());
1031 }
1032
1033 #[test]
1034 fn test_new_with_string() {
1035 let s = "c1";
1037 Field::new(s, DataType::Int64, false);
1038 }
1039
1040 #[test]
1041 fn test_new_dict_with_string() {
1042 let s = "c1";
1044 #[allow(deprecated)]
1045 Field::new_dict(s, DataType::Int64, false, 4, false);
1046 }
1047
1048 #[test]
1049 #[cfg_attr(miri, ignore)] fn test_debug_format_field() {
1051 insta::assert_debug_snapshot!(Field::new("item", DataType::UInt8, false), @r"
1053 Field {
1054 data_type: UInt8,
1055 }
1056 ");
1057 insta::assert_debug_snapshot!(Field::new("column", DataType::LargeUtf8, true), @r#"
1058 Field {
1059 name: "column",
1060 data_type: LargeUtf8,
1061 nullable: true,
1062 }
1063 "#);
1064 }
1065
1066 #[test]
1067 fn test_merge_incompatible_types() {
1068 let mut field = Field::new("c1", DataType::Int64, false);
1069 let result = field
1070 .try_merge(&Field::new("c1", DataType::Float32, true))
1071 .expect_err("should fail")
1072 .to_string();
1073 assert_eq!(
1074 "Schema error: Fail to merge schema field 'c1' because the from data_type = Float32 does not equal Int64",
1075 result
1076 );
1077 }
1078
1079 #[test]
1080 fn test_merge_with_null() {
1081 let mut field1 = Field::new("c1", DataType::Null, true);
1082 field1
1083 .try_merge(&Field::new("c1", DataType::Float32, false))
1084 .expect("should widen type to nullable float");
1085 assert_eq!(Field::new("c1", DataType::Float32, true), field1);
1086
1087 let mut field2 = Field::new("c2", DataType::Utf8, false);
1088 field2
1089 .try_merge(&Field::new("c2", DataType::Null, true))
1090 .expect("should widen type to nullable utf8");
1091 assert_eq!(Field::new("c2", DataType::Utf8, true), field2);
1092 }
1093
1094 #[test]
1095 fn test_merge_with_nested_null() {
1096 let mut struct1 = Field::new(
1097 "s1",
1098 DataType::Struct(Fields::from(vec![Field::new(
1099 "inner",
1100 DataType::Float32,
1101 false,
1102 )])),
1103 false,
1104 );
1105
1106 let struct2 = Field::new(
1107 "s2",
1108 DataType::Struct(Fields::from(vec![Field::new(
1109 "inner",
1110 DataType::Null,
1111 false,
1112 )])),
1113 true,
1114 );
1115
1116 struct1
1117 .try_merge(&struct2)
1118 .expect("should widen inner field's type to nullable float");
1119 assert_eq!(
1120 Field::new(
1121 "s1",
1122 DataType::Struct(Fields::from(vec![Field::new(
1123 "inner",
1124 DataType::Float32,
1125 true,
1126 )])),
1127 true,
1128 ),
1129 struct1
1130 );
1131
1132 let mut list1 = Field::new(
1133 "l1",
1134 DataType::List(Field::new("inner", DataType::Float32, false).into()),
1135 false,
1136 );
1137
1138 let list2 = Field::new(
1139 "l2",
1140 DataType::List(Field::new("inner", DataType::Null, false).into()),
1141 true,
1142 );
1143
1144 list1
1145 .try_merge(&list2)
1146 .expect("should widen inner field's type to nullable float");
1147 assert_eq!(
1148 Field::new(
1149 "l1",
1150 DataType::List(Field::new("inner", DataType::Float32, true).into()),
1151 true,
1152 ),
1153 list1
1154 );
1155
1156 let mut large_list1 = Field::new(
1157 "ll1",
1158 DataType::LargeList(Field::new("inner", DataType::Float32, false).into()),
1159 false,
1160 );
1161
1162 let large_list2 = Field::new(
1163 "ll2",
1164 DataType::LargeList(Field::new("inner", DataType::Null, false).into()),
1165 true,
1166 );
1167
1168 large_list1
1169 .try_merge(&large_list2)
1170 .expect("should widen inner field's type to nullable float");
1171 assert_eq!(
1172 Field::new(
1173 "ll1",
1174 DataType::LargeList(Field::new("inner", DataType::Float32, true).into()),
1175 true,
1176 ),
1177 large_list1
1178 );
1179 }
1180
1181 #[test]
1182 fn test_fields_with_dict_id() {
1183 #[allow(deprecated)]
1184 let dict1 = Field::new_dict(
1185 "dict1",
1186 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1187 false,
1188 10,
1189 false,
1190 );
1191 #[allow(deprecated)]
1192 let dict2 = Field::new_dict(
1193 "dict2",
1194 DataType::Dictionary(DataType::Int32.into(), DataType::Int8.into()),
1195 false,
1196 20,
1197 false,
1198 );
1199
1200 let field = Field::new(
1201 "struct<dict1, list[struct<dict2, list[struct<dict1]>]>",
1202 DataType::Struct(Fields::from(vec![
1203 dict1.clone(),
1204 Field::new(
1205 "list[struct<dict1, list[struct<dict2>]>]",
1206 DataType::List(Arc::new(Field::new(
1207 "struct<dict1, list[struct<dict2>]>",
1208 DataType::Struct(Fields::from(vec![
1209 dict1.clone(),
1210 Field::new(
1211 "list[struct<dict2>]",
1212 DataType::List(Arc::new(Field::new(
1213 "struct<dict2>",
1214 DataType::Struct(vec![dict2.clone()].into()),
1215 false,
1216 ))),
1217 false,
1218 ),
1219 ])),
1220 false,
1221 ))),
1222 false,
1223 ),
1224 ])),
1225 false,
1226 );
1227
1228 #[allow(deprecated)]
1229 for field in field.fields_with_dict_id(10) {
1230 assert_eq!(dict1, *field);
1231 }
1232 #[allow(deprecated)]
1233 for field in field.fields_with_dict_id(20) {
1234 assert_eq!(dict2, *field);
1235 }
1236 }
1237
1238 fn get_field_hash(field: &Field) -> u64 {
1239 let mut s = DefaultHasher::new();
1240 field.hash(&mut s);
1241 s.finish()
1242 }
1243
1244 #[test]
1245 fn test_field_comparison_case() {
1246 #[allow(deprecated)]
1248 let dict1 = Field::new_dict(
1249 "dict1",
1250 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1251 false,
1252 10,
1253 false,
1254 );
1255 #[allow(deprecated)]
1256 let dict2 = Field::new_dict(
1257 "dict1",
1258 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1259 false,
1260 20,
1261 false,
1262 );
1263
1264 assert_eq!(dict1, dict2);
1265 assert_eq!(get_field_hash(&dict1), get_field_hash(&dict2));
1266
1267 #[allow(deprecated)]
1268 let dict1 = Field::new_dict(
1269 "dict0",
1270 DataType::Dictionary(DataType::Utf8.into(), DataType::Int32.into()),
1271 false,
1272 10,
1273 false,
1274 );
1275
1276 assert_ne!(dict1, dict2);
1277 assert_ne!(get_field_hash(&dict1), get_field_hash(&dict2));
1278 }
1279
1280 #[test]
1281 fn test_field_comparison_metadata() {
1282 let f1 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1283 (String::from("k1"), String::from("v1")),
1284 (String::from("k2"), String::from("v2")),
1285 ]));
1286 let f2 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1287 (String::from("k1"), String::from("v1")),
1288 (String::from("k3"), String::from("v3")),
1289 ]));
1290 let f3 = Field::new("x", DataType::Binary, false).with_metadata(HashMap::from([
1291 (String::from("k1"), String::from("v1")),
1292 (String::from("k3"), String::from("v4")),
1293 ]));
1294
1295 assert!(f1.cmp(&f2).is_lt());
1296 assert!(f2.cmp(&f3).is_lt());
1297 assert!(f1.cmp(&f3).is_lt());
1298 }
1299
1300 #[test]
1301 #[expect(clippy::needless_borrows_for_generic_args)] fn test_field_as_ref() {
1303 let field = || Field::new("x", DataType::Binary, false);
1304
1305 fn accept_ref(_: impl AsRef<Field>) {}
1308
1309 accept_ref(field());
1310 accept_ref(&field());
1311 accept_ref(&&field());
1312 accept_ref(Arc::new(field()));
1313 accept_ref(&Arc::new(field()));
1314 accept_ref(&&Arc::new(field()));
1315
1316 fn accept_refs(_: impl IntoIterator<Item: AsRef<Field>>) {}
1319
1320 accept_refs(vec![field()]);
1321 accept_refs(vec![&field()]);
1322 accept_refs(vec![Arc::new(field())]);
1323 accept_refs(vec![&Arc::new(field())]);
1324 accept_refs(&vec![field()]);
1325 accept_refs(&vec![&field()]);
1326 accept_refs(&vec![Arc::new(field())]);
1327 accept_refs(&vec![&Arc::new(field())]);
1328 }
1329
1330 #[test]
1331 fn test_contains_reflexivity() {
1332 let mut field = Field::new("field1", DataType::Float16, false);
1333 field.set_metadata(HashMap::from([
1334 (String::from("k0"), String::from("v0")),
1335 (String::from("k1"), String::from("v1")),
1336 ]));
1337 assert!(field.contains(&field))
1338 }
1339
1340 #[test]
1341 fn test_contains_transitivity() {
1342 let child_field = Field::new("child1", DataType::Float16, false);
1343
1344 let mut field1 = Field::new(
1345 "field1",
1346 DataType::Struct(Fields::from(vec![child_field])),
1347 false,
1348 );
1349 field1.set_metadata(HashMap::from([(String::from("k1"), String::from("v1"))]));
1350
1351 let mut field2 = Field::new("field1", DataType::Struct(Fields::default()), true);
1352 field2.set_metadata(HashMap::from([(String::from("k2"), String::from("v2"))]));
1353 field2.try_merge(&field1).unwrap();
1354
1355 let mut field3 = Field::new("field1", DataType::Struct(Fields::default()), false);
1356 field3.set_metadata(HashMap::from([(String::from("k3"), String::from("v3"))]));
1357 field3.try_merge(&field2).unwrap();
1358
1359 assert!(field2.contains(&field1));
1360 assert!(field3.contains(&field2));
1361 assert!(field3.contains(&field1));
1362
1363 assert!(!field1.contains(&field2));
1364 assert!(!field1.contains(&field3));
1365 assert!(!field2.contains(&field3));
1366 }
1367
1368 #[test]
1369 fn test_contains_nullable() {
1370 let field1 = Field::new("field1", DataType::Boolean, true);
1371 let field2 = Field::new("field1", DataType::Boolean, false);
1372 assert!(field1.contains(&field2));
1373 assert!(!field2.contains(&field1));
1374 }
1375
1376 #[test]
1377 fn test_contains_must_have_same_fields() {
1378 let child_field1 = Field::new("child1", DataType::Float16, false);
1379 let child_field2 = Field::new("child2", DataType::Float16, false);
1380
1381 let field1 = Field::new(
1382 "field1",
1383 DataType::Struct(vec![child_field1.clone()].into()),
1384 true,
1385 );
1386 let field2 = Field::new(
1387 "field1",
1388 DataType::Struct(vec![child_field1, child_field2].into()),
1389 true,
1390 );
1391
1392 assert!(!field1.contains(&field2));
1393 assert!(!field2.contains(&field1));
1394
1395 let field1 = Field::new(
1397 "field1",
1398 DataType::Union(
1399 UnionFields::try_new(
1400 vec![1, 2],
1401 vec![
1402 Field::new("field1", DataType::UInt8, true),
1403 Field::new("field3", DataType::Utf8, false),
1404 ],
1405 )
1406 .unwrap(),
1407 UnionMode::Dense,
1408 ),
1409 true,
1410 );
1411 let field2 = Field::new(
1412 "field1",
1413 DataType::Union(
1414 UnionFields::try_new(
1415 vec![1, 3],
1416 vec![
1417 Field::new("field1", DataType::UInt8, false),
1418 Field::new("field3", DataType::Utf8, false),
1419 ],
1420 )
1421 .unwrap(),
1422 UnionMode::Dense,
1423 ),
1424 true,
1425 );
1426 assert!(!field1.contains(&field2));
1427
1428 let field1 = Field::new(
1430 "field1",
1431 DataType::Union(
1432 UnionFields::try_new(
1433 vec![1, 2],
1434 vec![
1435 Field::new("field1", DataType::UInt8, true),
1436 Field::new("field3", DataType::Utf8, false),
1437 ],
1438 )
1439 .unwrap(),
1440 UnionMode::Dense,
1441 ),
1442 true,
1443 );
1444 let field2 = Field::new(
1445 "field1",
1446 DataType::Union(
1447 UnionFields::try_new(
1448 vec![1, 2],
1449 vec![
1450 Field::new("field1", DataType::UInt8, false),
1451 Field::new("field3", DataType::Utf8, false),
1452 ],
1453 )
1454 .unwrap(),
1455 UnionMode::Dense,
1456 ),
1457 true,
1458 );
1459 assert!(field1.contains(&field2));
1460 }
1461
1462 #[cfg(feature = "serde")]
1463 fn assert_binary_serde_round_trip(field: Field) {
1464 let serialized = postcard::to_stdvec(&field).unwrap();
1465 let deserialized: Field = postcard::from_bytes(&serialized).unwrap();
1466 assert_eq!(field, deserialized)
1467 }
1468
1469 #[cfg(feature = "serde")]
1470 #[test]
1471 fn test_field_without_metadata_serde() {
1472 let field = Field::new("name", DataType::Boolean, true);
1473 assert_binary_serde_round_trip(field)
1474 }
1475
1476 #[cfg(feature = "serde")]
1477 #[test]
1478 fn test_field_with_empty_metadata_serde() {
1479 let field = Field::new("name", DataType::Boolean, false).with_metadata(HashMap::new());
1480
1481 assert_binary_serde_round_trip(field)
1482 }
1483
1484 #[cfg(feature = "serde")]
1485 #[test]
1486 fn test_field_with_nonempty_metadata_serde() {
1487 let mut metadata = HashMap::new();
1488 metadata.insert("hi".to_owned(), "".to_owned());
1489 let field = Field::new("name", DataType::Boolean, false).with_metadata(metadata);
1490
1491 assert_binary_serde_round_trip(field)
1492 }
1493
1494 #[test]
1495 fn test_merge_compound_with_null() {
1496 let mut field = Field::new(
1498 "s",
1499 DataType::Struct(Fields::from(vec![Field::new("a", DataType::Int32, false)])),
1500 false,
1501 );
1502 field
1503 .try_merge(&Field::new("s", DataType::Null, true))
1504 .expect("Struct should merge with Null");
1505 assert!(field.is_nullable());
1506 assert!(matches!(field.data_type(), DataType::Struct(_)));
1507
1508 let mut field = Field::new(
1510 "l",
1511 DataType::List(Field::new("item", DataType::Utf8, false).into()),
1512 false,
1513 );
1514 field
1515 .try_merge(&Field::new("l", DataType::Null, true))
1516 .expect("List should merge with Null");
1517 assert!(field.is_nullable());
1518 assert!(matches!(field.data_type(), DataType::List(_)));
1519
1520 let mut field = Field::new(
1522 "ll",
1523 DataType::LargeList(Field::new("item", DataType::Utf8, false).into()),
1524 false,
1525 );
1526 field
1527 .try_merge(&Field::new("ll", DataType::Null, true))
1528 .expect("LargeList should merge with Null");
1529 assert!(field.is_nullable());
1530 assert!(matches!(field.data_type(), DataType::LargeList(_)));
1531
1532 let mut field = Field::new(
1534 "u",
1535 DataType::Union(
1536 UnionFields::try_new(vec![0], vec![Field::new("f", DataType::Int32, false)])
1537 .unwrap(),
1538 UnionMode::Dense,
1539 ),
1540 false,
1541 );
1542 field
1543 .try_merge(&Field::new("u", DataType::Null, true))
1544 .expect("Union should merge with Null");
1545 assert!(matches!(field.data_type(), DataType::Union(_, _)));
1546 }
1547}