1use crate::{
38 ArrowError, DataType, Field, FieldRef, IntervalUnit, Schema, TimeUnit, UnionFields, UnionMode,
39};
40use bitflags::bitflags;
41use std::borrow::Cow;
42use std::sync::Arc;
43use std::{
44 collections::HashMap,
45 ffi::{CStr, CString, c_char, c_void},
46};
47
48bitflags! {
49 pub struct Flags: i64 {
54 const DICTIONARY_ORDERED = 0b00000001;
56 const NULLABLE = 0b00000010;
58 const MAP_KEYS_SORTED = 0b00000100;
60 }
61}
62
63#[repr(C)]
75#[derive(Debug)]
76#[allow(non_camel_case_types)]
77pub struct FFI_ArrowSchema {
78 pub format: *const c_char,
80 pub name: *const c_char,
82 pub metadata: *const c_char,
84 pub flags: i64,
87 pub n_children: i64,
89 pub children: *mut *mut FFI_ArrowSchema,
91 pub dictionary: *mut FFI_ArrowSchema,
93 pub release: Option<unsafe extern "C" fn(arg1: *mut FFI_ArrowSchema)>,
95 pub private_data: *mut c_void,
97}
98
99struct SchemaPrivateData {
100 children: Box<[*mut FFI_ArrowSchema]>,
101 dictionary: *mut FFI_ArrowSchema,
102 metadata: Option<Vec<u8>>,
103}
104
105unsafe extern "C" fn release_schema(schema: *mut FFI_ArrowSchema) {
107 if schema.is_null() {
108 return;
109 }
110 let schema = unsafe { &mut *schema };
111
112 drop(unsafe { CString::from_raw(schema.format as *mut c_char) });
114 if !schema.name.is_null() {
115 drop(unsafe { CString::from_raw(schema.name as *mut c_char) });
116 }
117 if !schema.private_data.is_null() {
118 let private_data = unsafe { Box::from_raw(schema.private_data as *mut SchemaPrivateData) };
119 for child in private_data.children.iter() {
120 drop(unsafe { Box::from_raw(*child) })
121 }
122 if !private_data.dictionary.is_null() {
123 drop(unsafe { Box::from_raw(private_data.dictionary) });
124 }
125
126 drop(private_data);
127 }
128
129 schema.release = None;
130}
131
132impl FFI_ArrowSchema {
133 pub fn try_new(
136 format: &str,
137 children: Vec<FFI_ArrowSchema>,
138 dictionary: Option<FFI_ArrowSchema>,
139 ) -> Result<Self, ArrowError> {
140 let mut this = Self::empty();
141
142 let children_ptr = children
143 .into_iter()
144 .map(Box::new)
145 .map(Box::into_raw)
146 .collect::<Box<_>>();
147
148 this.format = CString::new(format).unwrap().into_raw();
149 this.release = Some(release_schema);
150 this.n_children = children_ptr.len() as i64;
151
152 let dictionary_ptr = dictionary
153 .map(|d| Box::into_raw(Box::new(d)))
154 .unwrap_or(std::ptr::null_mut());
155
156 let mut private_data = Box::new(SchemaPrivateData {
157 children: children_ptr,
158 dictionary: dictionary_ptr,
159 metadata: None,
160 });
161
162 this.children = private_data.children.as_mut_ptr();
164
165 this.dictionary = dictionary_ptr;
166
167 this.private_data = Box::into_raw(private_data) as *mut c_void;
168
169 Ok(this)
170 }
171
172 pub fn with_name(mut self, name: &str) -> Result<Self, ArrowError> {
174 self.name = CString::new(name)
175 .map_err(|e| {
176 ArrowError::CDataInterface(format!(
177 "Null byte at position {} not allowed in name",
178 e.nul_position()
179 ))
180 })?
181 .into_raw();
182 Ok(self)
183 }
184
185 pub fn with_flags(mut self, flags: Flags) -> Result<Self, ArrowError> {
187 self.flags = flags.bits();
188 Ok(self)
189 }
190
191 pub fn with_metadata<I, S>(mut self, metadata: I) -> Result<Self, ArrowError>
193 where
194 I: IntoIterator<Item = (S, S)>,
195 S: AsRef<str>,
196 {
197 let metadata: Vec<(S, S)> = metadata.into_iter().collect();
198 let new_metadata = if !metadata.is_empty() {
200 let mut metadata_serialized: Vec<u8> = Vec::new();
201 let num_entries: i32 = metadata.len().try_into().map_err(|_| {
202 ArrowError::CDataInterface(format!(
203 "metadata can only have {} entries, but {} were provided",
204 i32::MAX,
205 metadata.len()
206 ))
207 })?;
208 metadata_serialized.extend(num_entries.to_ne_bytes());
209
210 for (key, value) in metadata.into_iter() {
211 let key_len: i32 = key.as_ref().len().try_into().map_err(|_| {
212 ArrowError::CDataInterface(format!(
213 "metadata key can only have {} bytes, but {} were provided",
214 i32::MAX,
215 key.as_ref().len()
216 ))
217 })?;
218 let value_len: i32 = value.as_ref().len().try_into().map_err(|_| {
219 ArrowError::CDataInterface(format!(
220 "metadata value can only have {} bytes, but {} were provided",
221 i32::MAX,
222 value.as_ref().len()
223 ))
224 })?;
225
226 metadata_serialized.extend(key_len.to_ne_bytes());
227 metadata_serialized.extend_from_slice(key.as_ref().as_bytes());
228 metadata_serialized.extend(value_len.to_ne_bytes());
229 metadata_serialized.extend_from_slice(value.as_ref().as_bytes());
230 }
231
232 self.metadata = metadata_serialized.as_ptr() as *const c_char;
233 Some(metadata_serialized)
234 } else {
235 self.metadata = std::ptr::null_mut();
236 None
237 };
238
239 unsafe {
240 let mut private_data = Box::from_raw(self.private_data as *mut SchemaPrivateData);
241 private_data.metadata = new_metadata;
242 self.private_data = Box::into_raw(private_data) as *mut c_void;
243 }
244
245 Ok(self)
246 }
247
248 pub unsafe fn from_raw(schema: *mut FFI_ArrowSchema) -> Self {
261 unsafe { std::ptr::replace(schema, Self::empty()) }
262 }
263
264 pub fn empty() -> Self {
266 Self {
267 format: std::ptr::null_mut(),
268 name: std::ptr::null_mut(),
269 metadata: std::ptr::null_mut(),
270 flags: 0,
271 n_children: 0,
272 children: std::ptr::null_mut(),
273 dictionary: std::ptr::null_mut(),
274 release: None,
275 private_data: std::ptr::null_mut(),
276 }
277 }
278
279 pub fn format(&self) -> &str {
281 assert!(!self.format.is_null());
282 unsafe { CStr::from_ptr(self.format) }
284 .to_str()
285 .expect("The external API has a non-utf8 as format")
286 }
287
288 pub fn name(&self) -> Option<&str> {
290 if self.name.is_null() {
291 None
292 } else {
293 Some(
295 unsafe { CStr::from_ptr(self.name) }
296 .to_str()
297 .expect("The external API has a non-utf8 as name"),
298 )
299 }
300 }
301
302 pub fn flags(&self) -> Option<Flags> {
304 Flags::from_bits(self.flags)
305 }
306
307 pub fn child(&self, index: usize) -> &Self {
315 assert!(index < self.n_children as usize);
316 unsafe { self.children.add(index).as_ref().unwrap().as_ref().unwrap() }
317 }
318
319 pub fn children(&self) -> impl Iterator<Item = &Self> {
321 (0..self.n_children as usize).map(move |i| self.child(i))
322 }
323
324 pub fn nullable(&self) -> bool {
327 (self.flags / 2) & 1 == 1
328 }
329
330 pub fn dictionary(&self) -> Option<&Self> {
335 unsafe { self.dictionary.as_ref() }
336 }
337
338 pub fn map_keys_sorted(&self) -> bool {
342 self.flags & 0b00000100 != 0
343 }
344
345 pub fn dictionary_ordered(&self) -> bool {
347 self.flags & 0b00000001 != 0
348 }
349
350 pub fn metadata(&self) -> Result<HashMap<String, String>, ArrowError> {
352 if self.metadata.is_null() {
353 Ok(HashMap::new())
354 } else {
355 let mut pos = 0;
356
357 #[allow(clippy::unnecessary_cast)]
361 let buffer: *const u8 = self.metadata as *const u8;
362
363 fn next_four_bytes(buffer: *const u8, pos: &mut isize) -> [u8; 4] {
364 let out = unsafe {
365 [
366 *buffer.offset(*pos),
367 *buffer.offset(*pos + 1),
368 *buffer.offset(*pos + 2),
369 *buffer.offset(*pos + 3),
370 ]
371 };
372 *pos += 4;
373 out
374 }
375
376 fn next_n_bytes(buffer: *const u8, pos: &mut isize, n: i32) -> &[u8] {
377 let out = unsafe {
378 std::slice::from_raw_parts(buffer.offset(*pos), n.try_into().unwrap())
379 };
380 *pos += isize::try_from(n).unwrap();
381 out
382 }
383
384 let num_entries = i32::from_ne_bytes(next_four_bytes(buffer, &mut pos));
385 if num_entries < 0 {
386 return Err(ArrowError::CDataInterface(
387 "Negative number of metadata entries".to_string(),
388 ));
389 }
390
391 let mut metadata =
392 HashMap::with_capacity(num_entries.try_into().expect("Too many metadata entries"));
393
394 for _ in 0..num_entries {
395 let key_length = i32::from_ne_bytes(next_four_bytes(buffer, &mut pos));
396 if key_length < 0 {
397 return Err(ArrowError::CDataInterface(
398 "Negative key length in metadata".to_string(),
399 ));
400 }
401 let key = String::from_utf8(next_n_bytes(buffer, &mut pos, key_length).to_vec())?;
402 let value_length = i32::from_ne_bytes(next_four_bytes(buffer, &mut pos));
403 if value_length < 0 {
404 return Err(ArrowError::CDataInterface(
405 "Negative value length in metadata".to_string(),
406 ));
407 }
408 let value =
409 String::from_utf8(next_n_bytes(buffer, &mut pos, value_length).to_vec())?;
410 metadata.insert(key, value);
411 }
412
413 Ok(metadata)
414 }
415 }
416}
417
418impl Drop for FFI_ArrowSchema {
419 fn drop(&mut self) {
420 match self.release {
421 None => (),
422 Some(release) => unsafe { release(self) },
423 };
424 }
425}
426
427unsafe impl Send for FFI_ArrowSchema {}
428
429impl TryFrom<&FFI_ArrowSchema> for DataType {
430 type Error = ArrowError;
431
432 fn try_from(c_schema: &FFI_ArrowSchema) -> Result<Self, ArrowError> {
434 let mut dtype = match c_schema.format() {
435 "n" => DataType::Null,
436 "b" => DataType::Boolean,
437 "c" => DataType::Int8,
438 "C" => DataType::UInt8,
439 "s" => DataType::Int16,
440 "S" => DataType::UInt16,
441 "i" => DataType::Int32,
442 "I" => DataType::UInt32,
443 "l" => DataType::Int64,
444 "L" => DataType::UInt64,
445 "e" => DataType::Float16,
446 "f" => DataType::Float32,
447 "g" => DataType::Float64,
448 "vz" => DataType::BinaryView,
449 "z" => DataType::Binary,
450 "Z" => DataType::LargeBinary,
451 "vu" => DataType::Utf8View,
452 "u" => DataType::Utf8,
453 "U" => DataType::LargeUtf8,
454 "tdD" => DataType::Date32,
455 "tdm" => DataType::Date64,
456 "tts" => DataType::Time32(TimeUnit::Second),
457 "ttm" => DataType::Time32(TimeUnit::Millisecond),
458 "ttu" => DataType::Time64(TimeUnit::Microsecond),
459 "ttn" => DataType::Time64(TimeUnit::Nanosecond),
460 "tDs" => DataType::Duration(TimeUnit::Second),
461 "tDm" => DataType::Duration(TimeUnit::Millisecond),
462 "tDu" => DataType::Duration(TimeUnit::Microsecond),
463 "tDn" => DataType::Duration(TimeUnit::Nanosecond),
464 "tiM" => DataType::Interval(IntervalUnit::YearMonth),
465 "tiD" => DataType::Interval(IntervalUnit::DayTime),
466 "tin" => DataType::Interval(IntervalUnit::MonthDayNano),
467 "+l" => {
468 let c_child = c_schema.child(0);
469 DataType::List(Arc::new(Field::try_from(c_child)?))
470 }
471 "+L" => {
472 let c_child = c_schema.child(0);
473 DataType::LargeList(Arc::new(Field::try_from(c_child)?))
474 }
475 "+vl" => {
476 let c_child = c_schema.child(0);
477 DataType::ListView(Arc::new(Field::try_from(c_child)?))
478 }
479 "+vL" => {
480 let c_child = c_schema.child(0);
481 DataType::LargeListView(Arc::new(Field::try_from(c_child)?))
482 }
483 "+s" => {
484 let fields = c_schema.children().map(Field::try_from);
485 DataType::Struct(fields.collect::<Result<_, ArrowError>>()?)
486 }
487 "+m" => {
488 let c_child = c_schema.child(0);
489 let map_keys_sorted = c_schema.map_keys_sorted();
490 DataType::Map(Arc::new(Field::try_from(c_child)?), map_keys_sorted)
491 }
492 "+r" => {
493 let c_run_ends = c_schema.child(0);
494 let c_values = c_schema.child(1);
495 DataType::RunEndEncoded(
496 Arc::new(Field::try_from(c_run_ends)?),
497 Arc::new(Field::try_from(c_values)?),
498 )
499 }
500 other => {
502 match other.splitn(2, ':').collect::<Vec<&str>>().as_slice() {
503 ["w", num_bytes] => {
505 let parsed_num_bytes = num_bytes.parse::<i32>().map_err(|_| {
506 ArrowError::CDataInterface(
507 "FixedSizeBinary requires an integer parameter representing number of bytes per element".to_string())
508 })?;
509 DataType::FixedSizeBinary(parsed_num_bytes)
510 }
511 ["+w", num_elems] => {
513 let c_child = c_schema.child(0);
514 let parsed_num_elems = num_elems.parse::<i32>().map_err(|_| {
515 ArrowError::CDataInterface(
516 "The FixedSizeList type requires an integer parameter representing number of elements per list".to_string())
517 })?;
518 DataType::FixedSizeList(
519 Arc::new(Field::try_from(c_child)?),
520 parsed_num_elems,
521 )
522 }
523 ["d", extra] => match extra.splitn(3, ',').collect::<Vec<&str>>().as_slice() {
525 [precision, scale] => {
526 let parsed_precision = precision.parse::<u8>().map_err(|_| {
527 ArrowError::CDataInterface(
528 "The decimal type requires an integer precision".to_string(),
529 )
530 })?;
531 let parsed_scale = scale.parse::<i8>().map_err(|_| {
532 ArrowError::CDataInterface(
533 "The decimal type requires an integer scale".to_string(),
534 )
535 })?;
536 DataType::Decimal128(parsed_precision, parsed_scale)
537 }
538 [precision, scale, bits] => {
539 let parsed_precision = precision.parse::<u8>().map_err(|_| {
540 ArrowError::CDataInterface(
541 "The decimal type requires an integer precision".to_string(),
542 )
543 })?;
544 let parsed_scale = scale.parse::<i8>().map_err(|_| {
545 ArrowError::CDataInterface(
546 "The decimal type requires an integer scale".to_string(),
547 )
548 })?;
549 match *bits {
550 "32" => DataType::Decimal32(parsed_precision, parsed_scale),
551 "64" => DataType::Decimal64(parsed_precision, parsed_scale),
552 "128" => DataType::Decimal128(parsed_precision, parsed_scale),
553 "256" => DataType::Decimal256(parsed_precision, parsed_scale),
554 _ => return Err(ArrowError::CDataInterface("Only 32/64/128/256 bit wide decimals are supported in the Rust implementation".to_string())),
555 }
556 }
557 _ => {
558 return Err(ArrowError::CDataInterface(format!(
559 "The decimal pattern \"d:{extra:?}\" is not supported in the Rust implementation"
560 )));
561 }
562 },
563 ["+ud", extra] => {
565 let type_ids = extra
566 .split(',')
567 .map(|t| {
568 t.parse::<i8>().map_err(|_| {
569 ArrowError::CDataInterface(
570 "The Union type requires an integer type id".to_string(),
571 )
572 })
573 })
574 .collect::<Result<Vec<_>, ArrowError>>()?;
575 let mut fields = Vec::with_capacity(type_ids.len());
576 for idx in 0..c_schema.n_children {
577 let c_child = c_schema.child(idx as usize);
578 let field = Field::try_from(c_child)?;
579 fields.push(field);
580 }
581
582 if fields.len() != type_ids.len() {
583 return Err(ArrowError::CDataInterface(
584 "The Union type requires same number of fields and type ids"
585 .to_string(),
586 ));
587 }
588
589 DataType::Union(UnionFields::try_new(type_ids, fields)?, UnionMode::Dense)
590 }
591 ["+us", extra] => {
593 let type_ids = extra
594 .split(',')
595 .map(|t| {
596 t.parse::<i8>().map_err(|_| {
597 ArrowError::CDataInterface(
598 "The Union type requires an integer type id".to_string(),
599 )
600 })
601 })
602 .collect::<Result<Vec<_>, ArrowError>>()?;
603 let mut fields = Vec::with_capacity(type_ids.len());
604 for idx in 0..c_schema.n_children {
605 let c_child = c_schema.child(idx as usize);
606 let field = Field::try_from(c_child)?;
607 fields.push(field);
608 }
609
610 if fields.len() != type_ids.len() {
611 return Err(ArrowError::CDataInterface(
612 "The Union type requires same number of fields and type ids"
613 .to_string(),
614 ));
615 }
616
617 DataType::Union(UnionFields::try_new(type_ids, fields)?, UnionMode::Sparse)
618 }
619
620 ["tss", ""] => DataType::Timestamp(TimeUnit::Second, None),
622 ["tsm", ""] => DataType::Timestamp(TimeUnit::Millisecond, None),
623 ["tsu", ""] => DataType::Timestamp(TimeUnit::Microsecond, None),
624 ["tsn", ""] => DataType::Timestamp(TimeUnit::Nanosecond, None),
625 ["tss", tz] => DataType::Timestamp(TimeUnit::Second, Some(Arc::from(*tz))),
626 ["tsm", tz] => DataType::Timestamp(TimeUnit::Millisecond, Some(Arc::from(*tz))),
627 ["tsu", tz] => DataType::Timestamp(TimeUnit::Microsecond, Some(Arc::from(*tz))),
628 ["tsn", tz] => DataType::Timestamp(TimeUnit::Nanosecond, Some(Arc::from(*tz))),
629 _ => {
630 return Err(ArrowError::CDataInterface(format!(
631 "The datatype \"{other:?}\" is still not supported in Rust implementation"
632 )));
633 }
634 }
635 }
636 };
637
638 if let Some(dict_schema) = c_schema.dictionary() {
639 let value_type = Self::try_from(dict_schema)?;
640 dtype = DataType::Dictionary(Box::new(dtype), Box::new(value_type));
641 }
642
643 Ok(dtype)
644 }
645}
646
647impl TryFrom<&FFI_ArrowSchema> for Field {
648 type Error = ArrowError;
649
650 fn try_from(c_schema: &FFI_ArrowSchema) -> Result<Self, ArrowError> {
651 let dtype = DataType::try_from(c_schema)?;
652 let field = Field::new(c_schema.name().unwrap_or(""), dtype, c_schema.nullable())
653 .with_dict_is_ordered(c_schema.dictionary_ordered())
654 .with_metadata(c_schema.metadata()?);
655 Ok(field)
656 }
657}
658
659impl TryFrom<&FFI_ArrowSchema> for Schema {
660 type Error = ArrowError;
661
662 fn try_from(c_schema: &FFI_ArrowSchema) -> Result<Self, ArrowError> {
663 let dtype = DataType::try_from(c_schema)?;
665 if let DataType::Struct(fields) = dtype {
666 Ok(Schema::new(fields).with_metadata(c_schema.metadata()?))
667 } else {
668 Err(ArrowError::CDataInterface(
669 "Unable to interpret C data struct as a Schema".to_string(),
670 ))
671 }
672 }
673}
674
675impl TryFrom<&DataType> for FFI_ArrowSchema {
676 type Error = ArrowError;
677
678 fn try_from(dtype: &DataType) -> Result<Self, ArrowError> {
680 let format = get_format_string(dtype)?;
681 let children = match dtype {
683 DataType::List(child)
684 | DataType::LargeList(child)
685 | DataType::ListView(child)
686 | DataType::LargeListView(child)
687 | DataType::FixedSizeList(child, _)
688 | DataType::Map(child, _) => {
689 vec![FFI_ArrowSchema::try_from(child.as_ref())?]
690 }
691 DataType::Union(fields, _) => fields
692 .iter()
693 .map(|(_, f)| f.as_ref().try_into())
694 .collect::<Result<Vec<_>, ArrowError>>()?,
695 DataType::Struct(fields) => fields
696 .iter()
697 .map(FFI_ArrowSchema::try_from)
698 .collect::<Result<Vec<_>, ArrowError>>()?,
699 DataType::RunEndEncoded(run_ends, values) => vec![
700 FFI_ArrowSchema::try_from(run_ends.as_ref())?,
701 FFI_ArrowSchema::try_from(values.as_ref())?,
702 ],
703 _ => vec![],
704 };
705 let dictionary = if let DataType::Dictionary(_, value_data_type) = dtype {
706 Some(Self::try_from(value_data_type.as_ref())?)
707 } else {
708 None
709 };
710
711 let flags = match dtype {
712 DataType::Map(_, true) => Flags::MAP_KEYS_SORTED,
713 _ => Flags::empty(),
714 };
715
716 FFI_ArrowSchema::try_new(&format, children, dictionary)?.with_flags(flags)
717 }
718}
719
720fn get_format_string(dtype: &DataType) -> Result<Cow<'static, str>, ArrowError> {
721 match dtype {
722 DataType::Null => Ok("n".into()),
723 DataType::Boolean => Ok("b".into()),
724 DataType::Int8 => Ok("c".into()),
725 DataType::UInt8 => Ok("C".into()),
726 DataType::Int16 => Ok("s".into()),
727 DataType::UInt16 => Ok("S".into()),
728 DataType::Int32 => Ok("i".into()),
729 DataType::UInt32 => Ok("I".into()),
730 DataType::Int64 => Ok("l".into()),
731 DataType::UInt64 => Ok("L".into()),
732 DataType::Float16 => Ok("e".into()),
733 DataType::Float32 => Ok("f".into()),
734 DataType::Float64 => Ok("g".into()),
735 DataType::BinaryView => Ok("vz".into()),
736 DataType::Binary => Ok("z".into()),
737 DataType::LargeBinary => Ok("Z".into()),
738 DataType::Utf8View => Ok("vu".into()),
739 DataType::Utf8 => Ok("u".into()),
740 DataType::LargeUtf8 => Ok("U".into()),
741 DataType::FixedSizeBinary(num_bytes) => Ok(Cow::Owned(format!("w:{num_bytes}"))),
742 DataType::FixedSizeList(_, num_elems) => Ok(Cow::Owned(format!("+w:{num_elems}"))),
743 DataType::Decimal32(precision, scale) => {
744 Ok(Cow::Owned(format!("d:{precision},{scale},32")))
745 }
746 DataType::Decimal64(precision, scale) => {
747 Ok(Cow::Owned(format!("d:{precision},{scale},64")))
748 }
749 DataType::Decimal128(precision, scale) => Ok(Cow::Owned(format!("d:{precision},{scale}"))),
750 DataType::Decimal256(precision, scale) => {
751 Ok(Cow::Owned(format!("d:{precision},{scale},256")))
752 }
753 DataType::Date32 => Ok("tdD".into()),
754 DataType::Date64 => Ok("tdm".into()),
755 DataType::Time32(TimeUnit::Second) => Ok("tts".into()),
756 DataType::Time32(TimeUnit::Millisecond) => Ok("ttm".into()),
757 DataType::Time64(TimeUnit::Microsecond) => Ok("ttu".into()),
758 DataType::Time64(TimeUnit::Nanosecond) => Ok("ttn".into()),
759 DataType::Timestamp(TimeUnit::Second, None) => Ok("tss:".into()),
760 DataType::Timestamp(TimeUnit::Millisecond, None) => Ok("tsm:".into()),
761 DataType::Timestamp(TimeUnit::Microsecond, None) => Ok("tsu:".into()),
762 DataType::Timestamp(TimeUnit::Nanosecond, None) => Ok("tsn:".into()),
763 DataType::Timestamp(TimeUnit::Second, Some(tz)) => Ok(Cow::Owned(format!("tss:{tz}"))),
764 DataType::Timestamp(TimeUnit::Millisecond, Some(tz)) => Ok(Cow::Owned(format!("tsm:{tz}"))),
765 DataType::Timestamp(TimeUnit::Microsecond, Some(tz)) => Ok(Cow::Owned(format!("tsu:{tz}"))),
766 DataType::Timestamp(TimeUnit::Nanosecond, Some(tz)) => Ok(Cow::Owned(format!("tsn:{tz}"))),
767 DataType::Duration(TimeUnit::Second) => Ok("tDs".into()),
768 DataType::Duration(TimeUnit::Millisecond) => Ok("tDm".into()),
769 DataType::Duration(TimeUnit::Microsecond) => Ok("tDu".into()),
770 DataType::Duration(TimeUnit::Nanosecond) => Ok("tDn".into()),
771 DataType::Interval(IntervalUnit::YearMonth) => Ok("tiM".into()),
772 DataType::Interval(IntervalUnit::DayTime) => Ok("tiD".into()),
773 DataType::Interval(IntervalUnit::MonthDayNano) => Ok("tin".into()),
774 DataType::List(_) => Ok("+l".into()),
775 DataType::LargeList(_) => Ok("+L".into()),
776 DataType::ListView(_) => Ok("+vl".into()),
777 DataType::LargeListView(_) => Ok("+vL".into()),
778 DataType::Struct(_) => Ok("+s".into()),
779 DataType::Map(_, _) => Ok("+m".into()),
780 DataType::RunEndEncoded(_, _) => Ok("+r".into()),
781 DataType::Dictionary(key_data_type, _) => get_format_string(key_data_type),
782 DataType::Union(fields, mode) => {
783 let formats = fields
784 .iter()
785 .map(|(t, _)| t.to_string())
786 .collect::<Vec<_>>();
787 match mode {
788 UnionMode::Dense => Ok(Cow::Owned(format!("{}:{}", "+ud", formats.join(",")))),
789 UnionMode::Sparse => Ok(Cow::Owned(format!("{}:{}", "+us", formats.join(",")))),
790 }
791 }
792 other => Err(ArrowError::CDataInterface(format!(
793 "The datatype \"{other:?}\" is still not supported in Rust implementation"
794 ))),
795 }
796}
797
798impl TryFrom<&FieldRef> for FFI_ArrowSchema {
799 type Error = ArrowError;
800
801 fn try_from(value: &FieldRef) -> Result<Self, Self::Error> {
802 value.as_ref().try_into()
803 }
804}
805
806impl TryFrom<&Field> for FFI_ArrowSchema {
807 type Error = ArrowError;
808
809 fn try_from(field: &Field) -> Result<Self, ArrowError> {
810 let mut flags = if field.is_nullable() {
811 Flags::NULLABLE
812 } else {
813 Flags::empty()
814 };
815
816 if let Some(true) = field.dict_is_ordered() {
817 flags |= Flags::DICTIONARY_ORDERED;
818 }
819
820 FFI_ArrowSchema::try_from(field.data_type())?
821 .with_name(field.name())?
822 .with_flags(flags)?
823 .with_metadata(field.metadata())
824 }
825}
826
827impl TryFrom<&Schema> for FFI_ArrowSchema {
828 type Error = ArrowError;
829
830 fn try_from(schema: &Schema) -> Result<Self, ArrowError> {
831 let dtype = DataType::Struct(schema.fields().clone());
832 let c_schema = FFI_ArrowSchema::try_from(&dtype)?.with_metadata(&schema.metadata)?;
833 Ok(c_schema)
834 }
835}
836
837impl TryFrom<DataType> for FFI_ArrowSchema {
838 type Error = ArrowError;
839
840 fn try_from(dtype: DataType) -> Result<Self, ArrowError> {
841 FFI_ArrowSchema::try_from(&dtype)
842 }
843}
844
845impl TryFrom<Field> for FFI_ArrowSchema {
846 type Error = ArrowError;
847
848 fn try_from(field: Field) -> Result<Self, ArrowError> {
849 FFI_ArrowSchema::try_from(&field)
850 }
851}
852
853impl TryFrom<Schema> for FFI_ArrowSchema {
854 type Error = ArrowError;
855
856 fn try_from(schema: Schema) -> Result<Self, ArrowError> {
857 FFI_ArrowSchema::try_from(&schema)
858 }
859}
860
861#[cfg(test)]
862mod tests {
863 use super::*;
864 use crate::Fields;
865
866 fn round_trip_type(dtype: DataType) {
867 let c_schema = FFI_ArrowSchema::try_from(&dtype).unwrap();
868 let restored = DataType::try_from(&c_schema).unwrap();
869 assert_eq!(restored, dtype);
870 }
871
872 fn round_trip_field(field: Field) {
873 let c_schema = FFI_ArrowSchema::try_from(&field).unwrap();
874 let restored = Field::try_from(&c_schema).unwrap();
875 assert_eq!(restored, field);
876 }
877
878 fn round_trip_schema(schema: Schema) {
879 let c_schema = FFI_ArrowSchema::try_from(&schema).unwrap();
880 let restored = Schema::try_from(&c_schema).unwrap();
881 assert_eq!(restored, schema);
882 }
883
884 #[test]
885 fn test_type() {
886 round_trip_type(DataType::Int64);
887 round_trip_type(DataType::UInt64);
888 round_trip_type(DataType::Float64);
889 round_trip_type(DataType::Date64);
890 round_trip_type(DataType::Time64(TimeUnit::Nanosecond));
891 round_trip_type(DataType::FixedSizeBinary(12));
892 round_trip_type(DataType::FixedSizeList(
893 Arc::new(Field::new("a", DataType::Int64, false)),
894 5,
895 ));
896 round_trip_type(DataType::Utf8);
897 round_trip_type(DataType::Utf8View);
898 round_trip_type(DataType::BinaryView);
899 round_trip_type(DataType::Binary);
900 round_trip_type(DataType::LargeBinary);
901 round_trip_type(DataType::List(Arc::new(Field::new(
902 "a",
903 DataType::Int16,
904 false,
905 ))));
906 round_trip_type(DataType::ListView(Arc::new(Field::new(
907 "a",
908 DataType::Int16,
909 false,
910 ))));
911 round_trip_type(DataType::LargeListView(Arc::new(Field::new(
912 "a",
913 DataType::Int16,
914 false,
915 ))));
916 round_trip_type(DataType::Struct(Fields::from(vec![Field::new(
917 "a",
918 DataType::Utf8,
919 true,
920 )])));
921 round_trip_type(DataType::RunEndEncoded(
922 Arc::new(Field::new("run_ends", DataType::Int32, false)),
923 Arc::new(Field::new("values", DataType::Binary, true)),
924 ));
925 }
926
927 #[test]
928 fn test_field() {
929 let dtype = DataType::Struct(vec![Field::new("a", DataType::Utf8, true)].into());
930 round_trip_field(Field::new("test", dtype, true));
931 }
932
933 #[test]
934 fn test_schema() {
935 let schema = Schema::new(vec![
936 Field::new("name", DataType::Utf8, false),
937 Field::new("address", DataType::Utf8, false),
938 Field::new("priority", DataType::UInt8, false),
939 ])
940 .with_metadata([("hello".to_string(), "world".to_string())].into());
941
942 round_trip_schema(schema);
943
944 let dtype = DataType::Struct(Fields::from(vec![
946 Field::new("a", DataType::Utf8, true),
947 Field::new("b", DataType::Int16, false),
948 ]));
949 let c_schema = FFI_ArrowSchema::try_from(&dtype).unwrap();
950 let schema = Schema::try_from(&c_schema).unwrap();
951 assert_eq!(schema.fields().len(), 2);
952
953 let c_schema = FFI_ArrowSchema::try_from(&DataType::Float64).unwrap();
955 let result = Schema::try_from(&c_schema);
956 assert!(result.is_err());
957 }
958
959 #[test]
960 fn test_map_keys_sorted() {
961 let keys = Field::new("keys", DataType::Int32, false);
962 let values = Field::new("values", DataType::UInt32, false);
963 let entry_struct = DataType::Struct(vec![keys, values].into());
964
965 let map_data_type =
967 DataType::Map(Arc::new(Field::new("entries", entry_struct, false)), true);
968
969 let arrow_schema = FFI_ArrowSchema::try_from(map_data_type).unwrap();
970 assert!(arrow_schema.map_keys_sorted());
971 }
972
973 #[test]
974 fn test_dictionary_ordered() {
975 #[allow(deprecated)]
976 let schema = Schema::new(vec![Field::new_dict(
977 "dict",
978 DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
979 false,
980 0,
981 true,
982 )]);
983
984 let arrow_schema = FFI_ArrowSchema::try_from(schema).unwrap();
985 assert!(arrow_schema.child(0).dictionary_ordered());
986
987 let field = Field::try_from(arrow_schema.child(0)).unwrap();
989 assert_eq!(field.dict_is_ordered(), Some(true));
990 }
991
992 #[test]
993 fn test_set_field_metadata() {
994 let metadata_cases: Vec<HashMap<String, String>> = vec![
995 [].into(),
996 [("key".to_string(), "value".to_string())].into(),
997 [
998 ("key".to_string(), "".to_string()),
999 ("ascii123".to_string(), "你好".to_string()),
1000 ("".to_string(), "value".to_string()),
1001 ]
1002 .into(),
1003 ];
1004
1005 let mut schema = FFI_ArrowSchema::try_new("b", vec![], None)
1006 .unwrap()
1007 .with_name("test")
1008 .unwrap();
1009
1010 for metadata in metadata_cases {
1011 schema = schema.with_metadata(&metadata).unwrap();
1012 let field = Field::try_from(&schema).unwrap();
1013 assert_eq!(field.metadata(), &metadata);
1014 }
1015 }
1016
1017 #[test]
1018 fn test_name_with_null_byte() {
1019 let schema = FFI_ArrowSchema::try_new("i", vec![], None).unwrap();
1020 assert!(schema.with_name("ab\0cd").is_err());
1021 }
1022
1023 #[test]
1024 fn test_import_field_with_null_name() {
1025 let dtype = DataType::Int16;
1026 let c_schema = FFI_ArrowSchema::try_from(&dtype).unwrap();
1027 assert!(c_schema.name().is_none());
1028 let field = Field::try_from(&c_schema).unwrap();
1029 assert_eq!(field.name(), "");
1030 }
1031}