1use std::{fmt::Display, iter::Peekable, str::Chars, sync::Arc};
19
20use crate::{
21 ArrowError, DECIMAL32_MAX_PRECISION, DECIMAL64_MAX_PRECISION, DECIMAL128_MAX_PRECISION,
22 DECIMAL256_MAX_PRECISION, DataType, Field, Fields, IntervalUnit, TimeUnit, UnionFields,
23 UnionMode,
24};
25
26pub(crate) fn parse_data_type(val: &str) -> ArrowResult<DataType> {
30 Parser::new(val).parse()
31}
32
33type ArrowResult<T> = Result<T, ArrowError>;
34
35fn make_error(val: &str, msg: &str) -> ArrowError {
36 let msg = format!(
37 "Unsupported type '{val}'. Must be a supported arrow type name such as 'Int32' or 'Timestamp(ns)'. Error {msg}"
38 );
39 ArrowError::ParseError(msg)
40}
41
42fn make_error_expected(val: &str, expected: &Token, actual: &Token) -> ArrowError {
43 make_error(val, &format!("Expected '{expected}', got '{actual}'"))
44}
45
46#[derive(Debug)]
48struct Parser<'a> {
49 val: &'a str,
50 tokenizer: Peekable<Tokenizer<'a>>,
51}
52
53impl<'a> Parser<'a> {
54 fn new(val: &'a str) -> Self {
55 Self {
56 val,
57 tokenizer: Tokenizer::new(val).peekable(),
58 }
59 }
60
61 fn parse(mut self) -> ArrowResult<DataType> {
62 let data_type = self.parse_next_type()?;
63 if self.tokenizer.next().is_some() {
65 Err(make_error(
66 self.val,
67 &format!("checking trailing content after parsing '{data_type}'"),
68 ))
69 } else {
70 Ok(data_type)
71 }
72 }
73
74 fn parse_next_type(&mut self) -> ArrowResult<DataType> {
76 match self.next_token()? {
77 Token::SimpleType(data_type) => Ok(data_type),
78 Token::Timestamp => self.parse_timestamp(),
79 Token::Time32 => self.parse_time32(),
80 Token::Time64 => self.parse_time64(),
81 Token::Duration => self.parse_duration(),
82 Token::Interval => self.parse_interval(),
83 Token::FixedSizeBinary => self.parse_fixed_size_binary(),
84 Token::Decimal32 => self.parse_decimal_32(),
85 Token::Decimal64 => self.parse_decimal_64(),
86 Token::Decimal128 => self.parse_decimal_128(),
87 Token::Decimal256 => self.parse_decimal_256(),
88 Token::Dictionary => self.parse_dictionary(),
89 Token::List => self.parse_list(),
90 Token::ListView => self.parse_list_view(),
91 Token::LargeList => self.parse_large_list(),
92 Token::LargeListView => self.parse_large_list_view(),
93 Token::FixedSizeList => self.parse_fixed_size_list(),
94 Token::Struct => self.parse_struct(),
95 Token::Union => self.parse_union(),
96 Token::Map => self.parse_map(),
97 Token::RunEndEncoded => self.parse_run_end_encoded(),
98 tok => Err(make_error(
99 self.val,
100 &format!("finding next type, got unexpected '{tok}'"),
101 )),
102 }
103 }
104
105 fn parse_field(&mut self) -> ArrowResult<Field> {
110 let name = self.parse_double_quoted_string("Field")?;
111 self.expect_token(Token::Colon)?;
112 let nullable = self.parse_opt_nullable();
113 let data_type = self.parse_next_type()?;
114 Ok(Field::new(name, data_type, nullable))
115 }
116
117 fn parse_list_field(&mut self, context: &str) -> ArrowResult<Field> {
123 let nullable = self.parse_opt_nullable();
124 let data_type = self.parse_next_type()?;
125
126 let field_name = if self
128 .tokenizer
129 .next_if(|next| matches!(next, Ok(Token::Comma)))
130 .is_none()
131 {
132 Field::LIST_FIELD_DEFAULT_NAME.into()
133 } else {
134 self.expect_token(Token::Field)?;
136 self.expect_token(Token::Colon)?;
137 self.parse_single_quoted_string(context)?
138 };
139
140 Ok(Field::new(field_name, data_type, nullable))
141 }
142
143 fn parse_list(&mut self) -> ArrowResult<DataType> {
146 self.expect_token(Token::LParen)?;
147 let field = self.parse_list_field("List")?;
148 self.expect_token(Token::RParen)?;
149 Ok(DataType::List(Arc::new(field)))
150 }
151
152 fn parse_list_view(&mut self) -> ArrowResult<DataType> {
155 self.expect_token(Token::LParen)?;
156 let field = self.parse_list_field("ListView")?;
157 self.expect_token(Token::RParen)?;
158 Ok(DataType::ListView(Arc::new(field)))
159 }
160
161 fn parse_large_list(&mut self) -> ArrowResult<DataType> {
164 self.expect_token(Token::LParen)?;
165 let field = self.parse_list_field("LargeList")?;
166 self.expect_token(Token::RParen)?;
167 Ok(DataType::LargeList(Arc::new(field)))
168 }
169
170 fn parse_large_list_view(&mut self) -> ArrowResult<DataType> {
173 self.expect_token(Token::LParen)?;
174 let field = self.parse_list_field("LargeListView")?;
175 self.expect_token(Token::RParen)?;
176 Ok(DataType::LargeListView(Arc::new(field)))
177 }
178
179 fn parse_fixed_size_list(&mut self) -> ArrowResult<DataType> {
186 self.expect_token(Token::LParen)?;
187 let length = self.parse_i32("FixedSizeList")?;
188 if length < 0 {
189 return Err(make_error(
190 self.val,
191 &format!("FixedSizeList length must be non-negative, got {length}"),
192 ));
193 }
194 match self.next_token()? {
195 Token::X => {
197 let field = self.parse_list_field("FixedSizeList")?;
198 self.expect_token(Token::RParen)?;
199 Ok(DataType::FixedSizeList(Arc::new(field), length))
200 }
201 Token::Comma => {
203 let data_type = self.parse_next_type()?;
204 self.expect_token(Token::RParen)?;
205 Ok(DataType::FixedSizeList(
206 Arc::new(Field::new_list_field(data_type, true)),
207 length,
208 ))
209 }
210 tok => Err(make_error(
211 self.val,
212 &format!("Expected 'x' or ',' after length for FixedSizeList, got '{tok}'"),
213 )),
214 }
215 }
216
217 fn parse_time_unit(&mut self, context: &str) -> ArrowResult<TimeUnit> {
219 match self.next_token()? {
220 Token::TimeUnit(time_unit) => Ok(time_unit),
221 tok => Err(make_error(
222 self.val,
223 &format!("finding TimeUnit for {context}, got {tok}"),
224 )),
225 }
226 }
227
228 fn parse_double_quoted_string(&mut self, context: &str) -> ArrowResult<String> {
230 let token = self.next_token()?;
231 if let Token::DoubleQuotedString(string) = token {
232 Ok(string)
233 } else {
234 Err(make_error(
235 self.val,
236 &format!("expected double quoted string for {context}, got '{token}'"),
237 ))
238 }
239 }
240
241 fn parse_single_quoted_string(&mut self, context: &str) -> ArrowResult<String> {
243 let token = self.next_token()?;
244 if let Token::SingleQuotedString(string) = token {
245 Ok(string)
246 } else {
247 Err(make_error(
248 self.val,
249 &format!("expected single quoted string for {context}, got '{token}'"),
250 ))
251 }
252 }
253
254 fn parse_i64(&mut self, context: &str) -> ArrowResult<i64> {
256 match self.next_token()? {
257 Token::Integer(v) => Ok(v),
258 tok => Err(make_error(
259 self.val,
260 &format!("finding i64 for {context}, got '{tok}'"),
261 )),
262 }
263 }
264
265 fn parse_i32(&mut self, context: &str) -> ArrowResult<i32> {
267 let length = self.parse_i64(context)?;
268 length.try_into().map_err(|e| {
269 make_error(
270 self.val,
271 &format!("converting {length} into i32 for {context}: {e}"),
272 )
273 })
274 }
275
276 fn parse_i8(&mut self, context: &str) -> ArrowResult<i8> {
278 let length = self.parse_i64(context)?;
279 length.try_into().map_err(|e| {
280 make_error(
281 self.val,
282 &format!("converting {length} into i8 for {context}: {e}"),
283 )
284 })
285 }
286
287 fn parse_u8(&mut self, context: &str) -> ArrowResult<u8> {
289 let length = self.parse_i64(context)?;
290 length.try_into().map_err(|e| {
291 make_error(
292 self.val,
293 &format!("converting {length} into u8 for {context}: {e}"),
294 )
295 })
296 }
297
298 fn parse_timestamp(&mut self) -> ArrowResult<DataType> {
300 self.expect_token(Token::LParen)?;
301 let time_unit = self.parse_time_unit("Timestamp")?;
302
303 let timezone;
304 match self.next_token()? {
305 Token::Comma => {
306 match self.next_token()? {
307 Token::None => {
309 timezone = None;
310 }
311 Token::Some => {
313 self.expect_token(Token::LParen)?;
314 timezone = Some(self.parse_double_quoted_string("Timezone")?);
315 self.expect_token(Token::RParen)?;
316 }
317 Token::DoubleQuotedString(tz) => {
318 timezone = Some(tz);
320 }
321 tok => {
322 return Err(make_error(
323 self.val,
324 &format!("Expected None, Some, or a timezone string, got {tok:?}"),
325 ));
326 }
327 }
328 self.expect_token(Token::RParen)?;
329 }
330 Token::RParen => {
332 timezone = None;
333 }
334 next_token => {
335 return Err(make_error(
336 self.val,
337 &format!("Expected comma followed by a timezone, or an ), got {next_token:?}"),
338 ));
339 }
340 }
341 Ok(DataType::Timestamp(time_unit, timezone.map(Into::into)))
342 }
343
344 fn parse_time32(&mut self) -> ArrowResult<DataType> {
346 self.expect_token(Token::LParen)?;
347 let time_unit = self.parse_time_unit("Time32")?;
348 match time_unit {
349 TimeUnit::Second | TimeUnit::Millisecond => (),
350 TimeUnit::Microsecond | TimeUnit::Nanosecond => {
351 return Err(make_error(
352 self.val,
353 &format!("Time32 time unit must be 's' or 'ms', got '{time_unit}'"),
354 ));
355 }
356 }
357 self.expect_token(Token::RParen)?;
358 Ok(DataType::Time32(time_unit))
359 }
360
361 fn parse_time64(&mut self) -> ArrowResult<DataType> {
363 self.expect_token(Token::LParen)?;
364 let time_unit = self.parse_time_unit("Time64")?;
365 match time_unit {
366 TimeUnit::Microsecond | TimeUnit::Nanosecond => (),
367 TimeUnit::Second | TimeUnit::Millisecond => {
368 return Err(make_error(
369 self.val,
370 &format!("Time64 time unit must be 'µs' or 'ns', got '{time_unit}'"),
371 ));
372 }
373 }
374 self.expect_token(Token::RParen)?;
375 Ok(DataType::Time64(time_unit))
376 }
377
378 fn parse_duration(&mut self) -> ArrowResult<DataType> {
380 self.expect_token(Token::LParen)?;
381 let time_unit = self.parse_time_unit("Duration")?;
382 self.expect_token(Token::RParen)?;
383 Ok(DataType::Duration(time_unit))
384 }
385
386 fn parse_interval(&mut self) -> ArrowResult<DataType> {
388 self.expect_token(Token::LParen)?;
389 let interval_unit = match self.next_token()? {
390 Token::IntervalUnit(interval_unit) => interval_unit,
391 tok => {
392 return Err(make_error(
393 self.val,
394 &format!("finding IntervalUnit for Interval, got {tok}"),
395 ));
396 }
397 };
398 self.expect_token(Token::RParen)?;
399 Ok(DataType::Interval(interval_unit))
400 }
401
402 fn parse_fixed_size_binary(&mut self) -> ArrowResult<DataType> {
404 self.expect_token(Token::LParen)?;
405 let length = self.parse_i32("FixedSizeBinary")?;
406 if length < 0 {
407 return Err(make_error(
408 self.val,
409 &format!("FixedSizeBinary length must be non-negative, got {length}"),
410 ));
411 }
412 self.expect_token(Token::RParen)?;
413 Ok(DataType::FixedSizeBinary(length))
414 }
415
416 fn validate_decimal(
417 &self,
418 precision: u8,
419 scale: i8,
420 type_name: &str,
421 max_precision: u8,
422 ) -> ArrowResult<()> {
423 if precision == 0 || precision > max_precision {
424 return Err(make_error(
425 self.val,
426 &format!(
427 "{type_name} precision must be in range [1, {max_precision}], got '{precision}'"
428 ),
429 ));
430 }
431 if scale > 0 && scale as u8 > precision {
432 return Err(make_error(
433 self.val,
434 &format!(
435 "{type_name} scale '{scale}' cannot be greater than precision '{precision}'"
436 ),
437 ));
438 }
439 Ok(())
440 }
441
442 fn parse_decimal_32(&mut self) -> ArrowResult<DataType> {
444 self.expect_token(Token::LParen)?;
445 let precision = self.parse_u8("Decimal32")?;
446 self.expect_token(Token::Comma)?;
447 let scale = self.parse_i8("Decimal32")?;
448 self.expect_token(Token::RParen)?;
449 self.validate_decimal(precision, scale, "Decimal32", DECIMAL32_MAX_PRECISION)?;
450 Ok(DataType::Decimal32(precision, scale))
451 }
452
453 fn parse_decimal_64(&mut self) -> ArrowResult<DataType> {
455 self.expect_token(Token::LParen)?;
456 let precision = self.parse_u8("Decimal64")?;
457 self.expect_token(Token::Comma)?;
458 let scale = self.parse_i8("Decimal64")?;
459 self.expect_token(Token::RParen)?;
460 self.validate_decimal(precision, scale, "Decimal64", DECIMAL64_MAX_PRECISION)?;
461 Ok(DataType::Decimal64(precision, scale))
462 }
463
464 fn parse_decimal_128(&mut self) -> ArrowResult<DataType> {
466 self.expect_token(Token::LParen)?;
467 let precision = self.parse_u8("Decimal128")?;
468 self.expect_token(Token::Comma)?;
469 let scale = self.parse_i8("Decimal128")?;
470 self.expect_token(Token::RParen)?;
471 self.validate_decimal(precision, scale, "Decimal128", DECIMAL128_MAX_PRECISION)?;
472 Ok(DataType::Decimal128(precision, scale))
473 }
474
475 fn parse_decimal_256(&mut self) -> ArrowResult<DataType> {
477 self.expect_token(Token::LParen)?;
478 let precision = self.parse_u8("Decimal256")?;
479 self.expect_token(Token::Comma)?;
480 let scale = self.parse_i8("Decimal256")?;
481 self.expect_token(Token::RParen)?;
482 self.validate_decimal(precision, scale, "Decimal256", DECIMAL256_MAX_PRECISION)?;
483 Ok(DataType::Decimal256(precision, scale))
484 }
485
486 fn parse_dictionary(&mut self) -> ArrowResult<DataType> {
488 self.expect_token(Token::LParen)?;
489 let key_type = self.parse_next_type()?;
490 self.expect_token(Token::Comma)?;
491 let value_type = self.parse_next_type()?;
492 self.expect_token(Token::RParen)?;
493 Ok(DataType::Dictionary(
494 Box::new(key_type),
495 Box::new(value_type),
496 ))
497 }
498
499 fn parse_struct(&mut self) -> ArrowResult<DataType> {
501 self.expect_token(Token::LParen)?;
502 let mut fields = Vec::new();
503 loop {
504 if self
505 .tokenizer
506 .next_if(|next| matches!(next, Ok(Token::RParen)))
507 .is_some()
508 {
509 break;
510 }
511
512 let field = self.parse_field()?;
513 fields.push(Arc::new(field));
514 match self.next_token()? {
515 Token::Comma => {}
516 Token::RParen => break,
517 tok => {
518 return Err(make_error(
519 self.val,
520 &format!(
521 "Unexpected token while parsing Struct fields. Expected ',' or ')', but got '{tok}'"
522 ),
523 ));
524 }
525 }
526 }
527 Ok(DataType::Struct(Fields::from(fields)))
528 }
529
530 fn parse_union(&mut self) -> ArrowResult<DataType> {
533 self.expect_token(Token::LParen)?;
534 let union_mode = self.parse_union_mode()?;
535 let mut type_ids = vec![];
536 let mut fields = vec![];
537 loop {
538 if self
539 .tokenizer
540 .next_if(|next| matches!(next, Ok(Token::RParen)))
541 .is_some()
542 {
543 break;
544 }
545 self.expect_token(Token::Comma)?;
546 let (type_id, field) = self.parse_union_field()?;
547 type_ids.push(type_id);
548 fields.push(field);
549 }
550 Ok(DataType::Union(
551 UnionFields::try_new(type_ids, fields)?,
552 union_mode,
553 ))
554 }
555
556 fn parse_union_mode(&mut self) -> ArrowResult<UnionMode> {
558 match self.next_token()? {
559 Token::UnionMode(union_mode) => Ok(union_mode),
560 tok => Err(make_error(
561 self.val,
562 &format!("finding UnionMode for Union, got {tok}"),
563 )),
564 }
565 }
566
567 fn parse_union_field(&mut self) -> ArrowResult<(i8, Field)> {
570 let type_id = self.parse_i8("UnionField")?;
571 self.expect_token(Token::Colon)?;
572 self.expect_token(Token::LParen)?;
573 let field = self.parse_field()?;
574 self.expect_token(Token::RParen)?;
575 Ok((type_id, field))
576 }
577
578 fn parse_map(&mut self) -> ArrowResult<DataType> {
581 self.expect_token(Token::LParen)?;
582 let field = self.parse_field()?;
583 if field.is_nullable() {
584 return Err(make_error(self.val, "Map entries field cannot be nullable"));
585 }
586 if let DataType::Struct(fields) = field.data_type() {
587 if fields.len() != 2 {
588 return Err(make_error(
589 self.val,
590 &format!(
591 "Map entries must contain two children, got {}",
592 fields.len()
593 ),
594 ));
595 }
596 if fields[0].is_nullable() {
597 return Err(make_error(self.val, "Map key field cannot be nullable"));
598 }
599 } else {
600 return Err(make_error(
601 self.val,
602 &format!(
603 "Map entries must be a Struct type, got {}",
604 field.data_type()
605 ),
606 ));
607 }
608 self.expect_token(Token::Comma)?;
609 let sorted = self.parse_map_sorted()?;
610 self.expect_token(Token::RParen)?;
611 Ok(DataType::Map(Arc::new(field), sorted))
612 }
613
614 fn parse_map_sorted(&mut self) -> ArrowResult<bool> {
616 match self.next_token()? {
617 Token::MapSorted(sorted) => Ok(sorted),
618 tok => Err(make_error(
619 self.val,
620 &format!("Expected sorted or unsorted for a map; got {tok:?}"),
621 )),
622 }
623 }
624
625 fn parse_run_end_encoded(&mut self) -> ArrowResult<DataType> {
630 self.expect_token(Token::LParen)?;
631
632 let verbose = matches!(
634 self.tokenizer.peek(),
635 Some(Ok(Token::DoubleQuotedString(_)))
636 );
637
638 let (run_ends, values) = if verbose {
639 let run_ends = self.parse_field()?;
640 if run_ends.is_nullable() {
641 return Err(make_error(
642 self.val,
643 "RunEndEncoded run_ends field cannot be nullable",
644 ));
645 }
646 self.expect_token(Token::Comma)?;
647 let values = self.parse_field()?;
648 (run_ends, values)
649 } else {
650 if self.parse_opt_nullable() {
651 return Err(make_error(
652 self.val,
653 "RunEndEncoded run_ends field cannot be nullable",
654 ));
655 }
656 let re_type = self.parse_next_type()?;
657 self.expect_token(Token::Comma)?;
658 let v_nullable = self.parse_opt_nullable();
659 let v_type = self.parse_next_type()?;
660 (
661 Field::new(Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME, re_type, false),
662 Field::new(Field::REE_VALUES_FIELD_DEFAULT_NAME, v_type, v_nullable),
663 )
664 };
665
666 self.expect_token(Token::RParen)?;
667 Ok(DataType::RunEndEncoded(
668 Arc::new(run_ends),
669 Arc::new(values),
670 ))
671 }
672
673 fn parse_opt_nullable(&mut self) -> bool {
675 let tok = self
676 .tokenizer
677 .next_if(|next| matches!(next, Ok(Token::NonNull | Token::Nullable)));
678 !matches!(tok, Some(Ok(Token::NonNull)))
679 }
680
681 fn next_token(&mut self) -> ArrowResult<Token> {
683 match self.tokenizer.next() {
684 None => Err(make_error(self.val, "finding next token")),
685 Some(token) => token,
686 }
687 }
688
689 fn expect_token(&mut self, tok: Token) -> ArrowResult<()> {
691 let next_token = self.next_token()?;
692 if next_token == tok {
693 Ok(())
694 } else {
695 Err(make_error_expected(self.val, &tok, &next_token))
696 }
697 }
698}
699
700fn is_separator(c: char) -> bool {
702 c == '(' || c == ')' || c == ',' || c == ':' || c == ' '
703}
704
705enum QuoteType {
706 Double,
707 Single,
708}
709
710#[derive(Debug)]
711struct Tokenizer<'a> {
720 val: &'a str,
721 chars: Peekable<Chars<'a>>,
722 word: String,
724}
725
726impl<'a> Tokenizer<'a> {
727 fn new(val: &'a str) -> Self {
728 Self {
729 val,
730 chars: val.chars().peekable(),
731 word: String::new(),
732 }
733 }
734
735 fn peek_next_char(&mut self) -> Option<char> {
737 self.chars.peek().copied()
738 }
739
740 fn next_char(&mut self) -> Option<char> {
742 self.chars.next()
743 }
744
745 fn parse_word(&mut self) -> ArrowResult<Token> {
748 self.word.clear();
750 loop {
751 match self.peek_next_char() {
752 None => break,
753 Some(c) if is_separator(c) => break,
754 Some(c) => {
755 self.next_char();
756 self.word.push(c);
757 }
758 }
759 }
760
761 if let Some(c) = self.word.chars().next() {
762 if c == '-' || c.is_numeric() {
764 let val: i64 = self.word.parse().map_err(|e| {
765 make_error(self.val, &format!("parsing {} as integer: {e}", self.word))
766 })?;
767 return Ok(Token::Integer(val));
768 }
769 }
770
771 let token = match self.word.as_str() {
773 "Null" => Token::SimpleType(DataType::Null),
774 "Boolean" => Token::SimpleType(DataType::Boolean),
775
776 "Int8" => Token::SimpleType(DataType::Int8),
777 "Int16" => Token::SimpleType(DataType::Int16),
778 "Int32" => Token::SimpleType(DataType::Int32),
779 "Int64" => Token::SimpleType(DataType::Int64),
780
781 "UInt8" => Token::SimpleType(DataType::UInt8),
782 "UInt16" => Token::SimpleType(DataType::UInt16),
783 "UInt32" => Token::SimpleType(DataType::UInt32),
784 "UInt64" => Token::SimpleType(DataType::UInt64),
785
786 "Utf8" => Token::SimpleType(DataType::Utf8),
787 "LargeUtf8" => Token::SimpleType(DataType::LargeUtf8),
788 "Utf8View" => Token::SimpleType(DataType::Utf8View),
789 "Binary" => Token::SimpleType(DataType::Binary),
790 "BinaryView" => Token::SimpleType(DataType::BinaryView),
791 "LargeBinary" => Token::SimpleType(DataType::LargeBinary),
792
793 "Float16" => Token::SimpleType(DataType::Float16),
794 "Float32" => Token::SimpleType(DataType::Float32),
795 "Float64" => Token::SimpleType(DataType::Float64),
796
797 "Date32" => Token::SimpleType(DataType::Date32),
798 "Date64" => Token::SimpleType(DataType::Date64),
799
800 "List" => Token::List,
801 "ListView" => Token::ListView,
802 "LargeList" => Token::LargeList,
803 "LargeListView" => Token::LargeListView,
804 "FixedSizeList" => Token::FixedSizeList,
805
806 "s" | "Second" => Token::TimeUnit(TimeUnit::Second),
807 "ms" | "Millisecond" => Token::TimeUnit(TimeUnit::Millisecond),
808 "µs" | "us" | "Microsecond" => Token::TimeUnit(TimeUnit::Microsecond),
809 "ns" | "Nanosecond" => Token::TimeUnit(TimeUnit::Nanosecond),
810
811 "Timestamp" => Token::Timestamp,
812 "Time32" => Token::Time32,
813 "Time64" => Token::Time64,
814 "Duration" => Token::Duration,
815 "Interval" => Token::Interval,
816 "Dictionary" => Token::Dictionary,
817
818 "FixedSizeBinary" => Token::FixedSizeBinary,
819
820 "Decimal32" => Token::Decimal32,
821 "Decimal64" => Token::Decimal64,
822 "Decimal128" => Token::Decimal128,
823 "Decimal256" => Token::Decimal256,
824
825 "YearMonth" => Token::IntervalUnit(IntervalUnit::YearMonth),
826 "DayTime" => Token::IntervalUnit(IntervalUnit::DayTime),
827 "MonthDayNano" => Token::IntervalUnit(IntervalUnit::MonthDayNano),
828
829 "Some" => Token::Some,
830 "None" => Token::None,
831
832 "non-null" => Token::NonNull,
833 "nullable" => Token::Nullable,
834 "field" => Token::Field,
835 "x" => Token::X,
836
837 "Struct" => Token::Struct,
838
839 "Union" => Token::Union,
840 "Sparse" => Token::UnionMode(UnionMode::Sparse),
841 "Dense" => Token::UnionMode(UnionMode::Dense),
842
843 "Map" => Token::Map,
844 "sorted" => Token::MapSorted(true),
845 "unsorted" => Token::MapSorted(false),
846
847 "RunEndEncoded" => Token::RunEndEncoded,
848
849 token => {
850 return Err(make_error(self.val, &format!("unknown token: {token}")));
851 }
852 };
853 Ok(token)
854 }
855
856 fn parse_quoted_string(&mut self, quote_type: QuoteType) -> ArrowResult<Token> {
858 let quote = match quote_type {
859 QuoteType::Double => '\"',
860 QuoteType::Single => '\'',
861 };
862
863 if self.next_char() != Some(quote) {
864 return Err(make_error(self.val, "Expected \""));
865 }
866
867 self.word.clear();
869
870 let mut is_escaped = false;
871
872 loop {
873 match self.next_char() {
874 None => {
875 return Err(ArrowError::ParseError(format!(
876 "Unterminated string at: \"{}",
877 self.word
878 )));
879 }
880 Some(c) => match c {
881 '\\' => {
882 is_escaped = true;
883 self.word.push(c);
884 }
885 c if c == quote => {
886 if is_escaped {
887 self.word.push(c);
888 is_escaped = false;
889 } else {
890 break;
891 }
892 }
893 c => {
894 self.word.push(c);
895 }
896 },
897 }
898 }
899
900 let val: String = self.word.parse().map_err(|err| {
901 ArrowError::ParseError(format!("Failed to parse string: \"{}\": {err}", self.word))
902 })?;
903
904 if val.is_empty() {
905 return Err(make_error(self.val, "empty strings aren't allowed"));
907 }
908
909 match quote_type {
910 QuoteType::Double => Ok(Token::DoubleQuotedString(val)),
911 QuoteType::Single => Ok(Token::SingleQuotedString(val)),
912 }
913 }
914}
915
916impl Iterator for Tokenizer<'_> {
917 type Item = ArrowResult<Token>;
918
919 fn next(&mut self) -> Option<Self::Item> {
920 loop {
921 match self.peek_next_char()? {
922 ' ' => {
923 self.next_char();
925 }
926 '"' => {
927 return Some(self.parse_quoted_string(QuoteType::Double));
928 }
929 '\'' => {
930 return Some(self.parse_quoted_string(QuoteType::Single));
931 }
932 '(' => {
933 self.next_char();
934 return Some(Ok(Token::LParen));
935 }
936 ')' => {
937 self.next_char();
938 return Some(Ok(Token::RParen));
939 }
940 ',' => {
941 self.next_char();
942 return Some(Ok(Token::Comma));
943 }
944 ':' => {
945 self.next_char();
946 return Some(Ok(Token::Colon));
947 }
948 _ => return Some(self.parse_word()),
949 }
950 }
951 }
952}
953
954#[derive(Debug, PartialEq)]
957enum Token {
958 SimpleType(DataType),
960 Timestamp,
961 Time32,
962 Time64,
963 Duration,
964 Interval,
965 FixedSizeBinary,
966 Decimal32,
967 Decimal64,
968 Decimal128,
969 Decimal256,
970 Dictionary,
971 TimeUnit(TimeUnit),
972 IntervalUnit(IntervalUnit),
973 LParen,
974 RParen,
975 Comma,
976 Colon,
977 Some,
978 None,
979 Integer(i64),
980 DoubleQuotedString(String),
981 SingleQuotedString(String),
982 List,
983 ListView,
984 LargeList,
985 LargeListView,
986 FixedSizeList,
987 Struct,
988 Union,
989 UnionMode(UnionMode),
990 Map,
991 MapSorted(bool),
992 RunEndEncoded,
993 NonNull,
994 Nullable,
995 Field,
996 X,
997}
998
999impl Display for Token {
1000 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1001 match self {
1002 Token::SimpleType(t) => write!(f, "{t}"),
1003 Token::List => write!(f, "List"),
1004 Token::ListView => write!(f, "ListView"),
1005 Token::LargeList => write!(f, "LargeList"),
1006 Token::LargeListView => write!(f, "LargeListView"),
1007 Token::FixedSizeList => write!(f, "FixedSizeList"),
1008 Token::Timestamp => write!(f, "Timestamp"),
1009 Token::Time32 => write!(f, "Time32"),
1010 Token::Time64 => write!(f, "Time64"),
1011 Token::Duration => write!(f, "Duration"),
1012 Token::Interval => write!(f, "Interval"),
1013 Token::TimeUnit(u) => write!(f, "TimeUnit({u:?})"),
1014 Token::IntervalUnit(u) => write!(f, "IntervalUnit({u:?})"),
1015 Token::LParen => write!(f, "("),
1016 Token::RParen => write!(f, ")"),
1017 Token::Comma => write!(f, ","),
1018 Token::Colon => write!(f, ":"),
1019 Token::Some => write!(f, "Some"),
1020 Token::None => write!(f, "None"),
1021 Token::FixedSizeBinary => write!(f, "FixedSizeBinary"),
1022 Token::Decimal32 => write!(f, "Decimal32"),
1023 Token::Decimal64 => write!(f, "Decimal64"),
1024 Token::Decimal128 => write!(f, "Decimal128"),
1025 Token::Decimal256 => write!(f, "Decimal256"),
1026 Token::Dictionary => write!(f, "Dictionary"),
1027 Token::Integer(v) => write!(f, "Integer({v})"),
1028 Token::DoubleQuotedString(s) => write!(f, "DoubleQuotedString({s})"),
1029 Token::SingleQuotedString(s) => write!(f, "SingleQuotedString({s})"),
1030 Token::Struct => write!(f, "Struct"),
1031 Token::Union => write!(f, "Union"),
1032 Token::UnionMode(m) => write!(f, "{m:?}"),
1033 Token::Map => write!(f, "Map"),
1034 Token::MapSorted(sorted) => {
1035 write!(f, "{}", if *sorted { "sorted" } else { "unsorted" })
1036 }
1037 Token::RunEndEncoded => write!(f, "RunEndEncoded"),
1038 Token::NonNull => write!(f, "non-null"),
1039 Token::Nullable => write!(f, "nullable"),
1040 Token::Field => write!(f, "field"),
1041 Token::X => write!(f, "x"),
1042 }
1043 }
1044}
1045
1046#[cfg(test)]
1047mod test {
1048 use super::*;
1049
1050 #[test]
1051 fn test_parse_data_type() {
1052 for dt in list_datatypes() {
1054 round_trip(dt)
1055 }
1056 }
1057
1058 fn round_trip(data_type: DataType) {
1061 let data_type_string = data_type.to_string();
1062 println!("Input '{data_type_string}' ({data_type:?})");
1063 let parsed_type = parse_data_type(&data_type_string).unwrap();
1064 assert_eq!(
1065 data_type, parsed_type,
1066 "Mismatch parsing {data_type_string}"
1067 );
1068 }
1069
1070 fn list_datatypes() -> Vec<DataType> {
1071 vec![
1072 DataType::Null,
1076 DataType::Boolean,
1077 DataType::Int8,
1078 DataType::Int16,
1079 DataType::Int32,
1080 DataType::Int64,
1081 DataType::UInt8,
1082 DataType::UInt16,
1083 DataType::UInt32,
1084 DataType::UInt64,
1085 DataType::Float16,
1086 DataType::Float32,
1087 DataType::Float64,
1088 DataType::Timestamp(TimeUnit::Second, None),
1089 DataType::Timestamp(TimeUnit::Millisecond, None),
1090 DataType::Timestamp(TimeUnit::Microsecond, None),
1091 DataType::Timestamp(TimeUnit::Nanosecond, None),
1092 DataType::Timestamp(TimeUnit::Nanosecond, Some("+00:00".into())),
1094 DataType::Timestamp(TimeUnit::Microsecond, Some("+00:00".into())),
1095 DataType::Timestamp(TimeUnit::Millisecond, Some("+00:00".into())),
1096 DataType::Timestamp(TimeUnit::Second, Some("+00:00".into())),
1097 DataType::Timestamp(TimeUnit::Nanosecond, Some("+08:00".into())),
1098 DataType::Timestamp(TimeUnit::Microsecond, Some("+08:00".into())),
1099 DataType::Timestamp(TimeUnit::Millisecond, Some("+08:00".into())),
1100 DataType::Timestamp(TimeUnit::Second, Some("+08:00".into())),
1101 DataType::Date32,
1102 DataType::Date64,
1103 DataType::Time32(TimeUnit::Second),
1104 DataType::Time32(TimeUnit::Millisecond),
1105 DataType::Time64(TimeUnit::Microsecond),
1106 DataType::Time64(TimeUnit::Nanosecond),
1107 DataType::Duration(TimeUnit::Second),
1108 DataType::Duration(TimeUnit::Millisecond),
1109 DataType::Duration(TimeUnit::Microsecond),
1110 DataType::Duration(TimeUnit::Nanosecond),
1111 DataType::Interval(IntervalUnit::YearMonth),
1112 DataType::Interval(IntervalUnit::DayTime),
1113 DataType::Interval(IntervalUnit::MonthDayNano),
1114 DataType::Binary,
1115 DataType::BinaryView,
1116 DataType::FixedSizeBinary(0),
1117 DataType::FixedSizeBinary(1234),
1118 DataType::LargeBinary,
1119 DataType::Utf8,
1120 DataType::Utf8View,
1121 DataType::LargeUtf8,
1122 DataType::Decimal32(7, 6),
1123 DataType::Decimal64(6, 5),
1124 DataType::Decimal128(7, 6),
1125 DataType::Decimal256(6, 5),
1126 DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1130 DataType::Dictionary(Box::new(DataType::Int8), Box::new(DataType::Utf8)),
1131 DataType::Dictionary(
1132 Box::new(DataType::Int8),
1133 Box::new(DataType::Timestamp(TimeUnit::Nanosecond, None)),
1134 ),
1135 DataType::Dictionary(
1136 Box::new(DataType::Int8),
1137 Box::new(DataType::FixedSizeBinary(23)),
1138 ),
1139 DataType::Dictionary(
1140 Box::new(DataType::Int8),
1141 Box::new(
1142 DataType::Dictionary(Box::new(DataType::Int8), Box::new(DataType::Utf8)),
1144 ),
1145 ),
1146 DataType::Struct(Fields::from(vec![
1147 Field::new("f1", DataType::Int64, true),
1148 Field::new("f2", DataType::Float64, true),
1149 Field::new(
1150 "f3",
1151 DataType::Timestamp(TimeUnit::Second, Some("+08:00".into())),
1152 true,
1153 ),
1154 Field::new(
1155 "f4",
1156 DataType::Dictionary(
1157 Box::new(DataType::Int8),
1158 Box::new(DataType::FixedSizeBinary(23)),
1159 ),
1160 true,
1161 ),
1162 ])),
1163 DataType::Struct(Fields::from(vec![
1164 Field::new("Int64", DataType::Int64, true),
1165 Field::new("Float64", DataType::Float64, true),
1166 ])),
1167 DataType::Struct(Fields::from(vec![
1168 Field::new("f1", DataType::Int64, true),
1169 Field::new(
1170 "nested_struct",
1171 DataType::Struct(Fields::from(vec![Field::new("n1", DataType::Int64, true)])),
1172 true,
1173 ),
1174 ])),
1175 DataType::Struct(Fields::from(vec![Field::new("f1", DataType::Int64, true)])),
1176 DataType::Struct(Fields::empty()),
1177 DataType::List(Arc::new(Field::new_list_field(DataType::Int64, true))),
1178 DataType::List(Arc::new(Field::new_list_field(DataType::Int64, false))),
1179 DataType::List(Arc::new(Field::new("Int64", DataType::Int64, true))),
1180 DataType::List(Arc::new(Field::new("Int64", DataType::Int64, false))),
1181 DataType::List(Arc::new(Field::new(
1182 "nested_list",
1183 DataType::List(Arc::new(Field::new("Int64", DataType::Int64, true))),
1184 true,
1185 ))),
1186 DataType::ListView(Arc::new(Field::new_list_field(DataType::Int64, true))),
1187 DataType::ListView(Arc::new(Field::new_list_field(DataType::Int64, false))),
1188 DataType::ListView(Arc::new(Field::new("Int64", DataType::Int64, true))),
1189 DataType::ListView(Arc::new(Field::new("Int64", DataType::Int64, false))),
1190 DataType::ListView(Arc::new(Field::new(
1191 "nested_list_view",
1192 DataType::ListView(Arc::new(Field::new("Int64", DataType::Int64, true))),
1193 true,
1194 ))),
1195 DataType::LargeList(Arc::new(Field::new_list_field(DataType::Int64, true))),
1196 DataType::LargeList(Arc::new(Field::new_list_field(DataType::Int64, false))),
1197 DataType::LargeList(Arc::new(Field::new("Int64", DataType::Int64, true))),
1198 DataType::LargeList(Arc::new(Field::new("Int64", DataType::Int64, false))),
1199 DataType::LargeList(Arc::new(Field::new(
1200 "nested_large_list",
1201 DataType::LargeList(Arc::new(Field::new("Int64", DataType::Int64, true))),
1202 true,
1203 ))),
1204 DataType::LargeListView(Arc::new(Field::new_list_field(DataType::Int64, true))),
1205 DataType::LargeListView(Arc::new(Field::new_list_field(DataType::Int64, false))),
1206 DataType::LargeListView(Arc::new(Field::new("Int64", DataType::Int64, true))),
1207 DataType::LargeListView(Arc::new(Field::new("Int64", DataType::Int64, false))),
1208 DataType::LargeListView(Arc::new(Field::new(
1209 "nested_large_list_view",
1210 DataType::LargeListView(Arc::new(Field::new("Int64", DataType::Int64, true))),
1211 true,
1212 ))),
1213 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int64, true)), 2),
1214 DataType::FixedSizeList(Arc::new(Field::new_list_field(DataType::Int64, false)), 2),
1215 DataType::FixedSizeList(Arc::new(Field::new("Int64", DataType::Int64, true)), 2),
1216 DataType::FixedSizeList(Arc::new(Field::new("Int64", DataType::Int64, false)), 2),
1217 DataType::FixedSizeList(
1218 Arc::new(Field::new(
1219 "nested_fixed_size_list",
1220 DataType::FixedSizeList(
1221 Arc::new(Field::new("Int64", DataType::Int64, true)),
1222 2,
1223 ),
1224 true,
1225 )),
1226 2,
1227 ),
1228 DataType::Union(
1229 UnionFields::from_fields(vec![
1230 Field::new("Int32", DataType::Int32, false),
1231 Field::new("Utf8", DataType::Utf8, true),
1232 ]),
1233 UnionMode::Sparse,
1234 ),
1235 DataType::Union(
1236 UnionFields::from_fields(vec![
1237 Field::new("Int32", DataType::Int32, false),
1238 Field::new("Utf8", DataType::Utf8, true),
1239 ]),
1240 UnionMode::Dense,
1241 ),
1242 DataType::Union(
1243 UnionFields::from_fields(vec![
1244 Field::new_union(
1245 "nested_union",
1246 vec![0, 1],
1247 vec![
1248 Field::new("Int32", DataType::Int32, false),
1249 Field::new("Utf8", DataType::Utf8, true),
1250 ],
1251 UnionMode::Dense,
1252 ),
1253 Field::new("Utf8", DataType::Utf8, true),
1254 ]),
1255 UnionMode::Sparse,
1256 ),
1257 DataType::Union(
1258 UnionFields::from_fields(vec![Field::new("Int32", DataType::Int32, false)]),
1259 UnionMode::Dense,
1260 ),
1261 DataType::Union(
1262 UnionFields::try_new(Vec::<i8>::new(), Vec::<Field>::new()).unwrap(),
1263 UnionMode::Sparse,
1264 ),
1265 DataType::RunEndEncoded(
1266 Arc::new(Field::new(
1267 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1268 DataType::UInt32,
1269 false,
1270 )),
1271 Arc::new(Field::new(
1272 Field::REE_VALUES_FIELD_DEFAULT_NAME,
1273 DataType::Int32,
1274 true,
1275 )),
1276 ),
1277 DataType::RunEndEncoded(
1278 Arc::new(Field::new(
1279 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1280 DataType::RunEndEncoded(
1281 Arc::new(Field::new(
1282 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1283 DataType::UInt32,
1284 false,
1285 )),
1286 Arc::new(Field::new(
1287 Field::REE_VALUES_FIELD_DEFAULT_NAME,
1288 DataType::Int32,
1289 true,
1290 )),
1291 ),
1292 false,
1293 )),
1294 Arc::new(Field::new(
1295 Field::REE_VALUES_FIELD_DEFAULT_NAME,
1296 DataType::Int32,
1297 true,
1298 )),
1299 ),
1300 DataType::RunEndEncoded(
1302 Arc::new(Field::new(
1303 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1304 DataType::RunEndEncoded(
1305 Arc::new(Field::new(
1306 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1307 DataType::UInt32,
1308 false,
1309 )),
1310 Arc::new(Field::new(
1311 Field::REE_VALUES_FIELD_DEFAULT_NAME,
1312 DataType::Int32,
1313 true,
1314 )),
1315 ),
1316 false,
1317 )),
1318 Arc::new(Field::new("named_values", DataType::Int32, false)),
1319 ),
1320 DataType::RunEndEncoded(
1322 Arc::new(Field::new(
1323 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1324 DataType::RunEndEncoded(
1325 Arc::new(Field::new(
1326 Field::REE_RUN_ENDS_FIELD_DEFAULT_NAME,
1327 DataType::UInt32,
1328 false,
1329 )),
1330 Arc::new(Field::new(
1331 Field::REE_VALUES_FIELD_DEFAULT_NAME,
1332 DataType::Int32,
1333 false,
1334 )),
1335 ),
1336 false,
1337 )),
1338 Arc::new(Field::new("named_values", DataType::Int32, false)),
1339 ),
1340 ]
1341 }
1342
1343 #[test]
1344 fn test_parse_data_type_whitespace_tolerance() {
1345 let cases = [
1347 ("Int8", DataType::Int8),
1348 (
1349 "Timestamp (ns)",
1350 DataType::Timestamp(TimeUnit::Nanosecond, None),
1351 ),
1352 (
1353 "Timestamp (ns) ",
1354 DataType::Timestamp(TimeUnit::Nanosecond, None),
1355 ),
1356 (
1357 " Timestamp (ns )",
1358 DataType::Timestamp(TimeUnit::Nanosecond, None),
1359 ),
1360 (
1361 "Timestamp (ns ) ",
1362 DataType::Timestamp(TimeUnit::Nanosecond, None),
1363 ),
1364 ];
1365
1366 for (data_type_string, expected_data_type) in cases {
1367 let parsed_data_type = parse_data_type(data_type_string).unwrap();
1368 assert_eq!(
1369 parsed_data_type, expected_data_type,
1370 "Parsing '{data_type_string}', expecting '{expected_data_type}'"
1371 );
1372 }
1373 }
1374
1375 #[test]
1377 fn test_parse_data_type_backwards_compatibility() {
1378 use DataType::*;
1379 use IntervalUnit::*;
1380 use TimeUnit::*;
1381 for t in list_datatypes() {
1383 println!(r#"("{t}", {t:?}),"#);
1384 }
1385 let cases = [
1387 ("Timestamp(Nanosecond, None)", Timestamp(Nanosecond, None)),
1388 ("Timestamp(Microsecond, None)", Timestamp(Microsecond, None)),
1389 ("Timestamp(Millisecond, None)", Timestamp(Millisecond, None)),
1390 ("Timestamp(Second, None)", Timestamp(Second, None)),
1391 ("Timestamp(Nanosecond, None)", Timestamp(Nanosecond, None)),
1392 (
1394 r#"Timestamp(Nanosecond, Some("+00:00"))"#,
1395 Timestamp(Nanosecond, Some("+00:00".into())),
1396 ),
1397 (
1398 r#"Timestamp(Microsecond, Some("+00:00"))"#,
1399 Timestamp(Microsecond, Some("+00:00".into())),
1400 ),
1401 (
1402 r#"Timestamp(Millisecond, Some("+00:00"))"#,
1403 Timestamp(Millisecond, Some("+00:00".into())),
1404 ),
1405 (
1406 r#"Timestamp(Second, Some("+00:00"))"#,
1407 Timestamp(Second, Some("+00:00".into())),
1408 ),
1409 ("Null", Null),
1410 ("Boolean", Boolean),
1411 ("Int8", Int8),
1412 ("Int16", Int16),
1413 ("Int32", Int32),
1414 ("Int64", Int64),
1415 ("UInt8", UInt8),
1416 ("UInt16", UInt16),
1417 ("UInt32", UInt32),
1418 ("UInt64", UInt64),
1419 ("Float16", Float16),
1420 ("Float32", Float32),
1421 ("Float64", Float64),
1422 ("Timestamp(s)", Timestamp(Second, None)),
1423 ("Timestamp(ms)", Timestamp(Millisecond, None)),
1424 ("Timestamp(µs)", Timestamp(Microsecond, None)),
1425 ("Timestamp(ns)", Timestamp(Nanosecond, None)),
1426 (
1427 r#"Timestamp(ns, "+00:00")"#,
1428 Timestamp(Nanosecond, Some("+00:00".into())),
1429 ),
1430 (
1431 r#"Timestamp(µs, "+00:00")"#,
1432 Timestamp(Microsecond, Some("+00:00".into())),
1433 ),
1434 (
1435 r#"Timestamp(ms, "+00:00")"#,
1436 Timestamp(Millisecond, Some("+00:00".into())),
1437 ),
1438 (
1439 r#"Timestamp(s, "+00:00")"#,
1440 Timestamp(Second, Some("+00:00".into())),
1441 ),
1442 (
1443 r#"Timestamp(ns, "+08:00")"#,
1444 Timestamp(Nanosecond, Some("+08:00".into())),
1445 ),
1446 (
1447 r#"Timestamp(µs, "+08:00")"#,
1448 Timestamp(Microsecond, Some("+08:00".into())),
1449 ),
1450 (
1451 r#"Timestamp(ms, "+08:00")"#,
1452 Timestamp(Millisecond, Some("+08:00".into())),
1453 ),
1454 (
1455 r#"Timestamp(s, "+08:00")"#,
1456 Timestamp(Second, Some("+08:00".into())),
1457 ),
1458 ("Date32", Date32),
1459 ("Date64", Date64),
1460 ("Time32(s)", Time32(Second)),
1461 ("Time32(ms)", Time32(Millisecond)),
1462 ("Time64(µs)", Time64(Microsecond)),
1463 ("Time64(ns)", Time64(Nanosecond)),
1464 ("Duration(s)", Duration(Second)),
1465 ("Duration(ms)", Duration(Millisecond)),
1466 ("Duration(µs)", Duration(Microsecond)),
1467 ("Duration(ns)", Duration(Nanosecond)),
1468 ("Interval(YearMonth)", Interval(YearMonth)),
1469 ("Interval(DayTime)", Interval(DayTime)),
1470 ("Interval(MonthDayNano)", Interval(MonthDayNano)),
1471 ("Binary", Binary),
1472 ("BinaryView", BinaryView),
1473 ("FixedSizeBinary(0)", FixedSizeBinary(0)),
1474 ("FixedSizeBinary(1234)", FixedSizeBinary(1234)),
1475 ("LargeBinary", LargeBinary),
1476 ("Utf8", Utf8),
1477 ("Utf8View", Utf8View),
1478 ("LargeUtf8", LargeUtf8),
1479 ("Decimal32(7, 6)", Decimal32(7, 6)),
1480 ("Decimal64(6, 5)", Decimal64(6, 5)),
1481 ("Decimal128(7, 6)", Decimal128(7, 6)),
1482 ("Decimal256(6, 5)", Decimal256(6, 5)),
1483 (
1484 "Dictionary(Int32, Utf8)",
1485 Dictionary(Box::new(Int32), Box::new(Utf8)),
1486 ),
1487 (
1488 "Dictionary(Int8, Utf8)",
1489 Dictionary(Box::new(Int8), Box::new(Utf8)),
1490 ),
1491 (
1492 "Dictionary(Int8, Timestamp(ns))",
1493 Dictionary(Box::new(Int8), Box::new(Timestamp(Nanosecond, None))),
1494 ),
1495 (
1496 "Dictionary(Int8, FixedSizeBinary(23))",
1497 Dictionary(Box::new(Int8), Box::new(FixedSizeBinary(23))),
1498 ),
1499 (
1500 "Dictionary(Int8, Dictionary(Int8, Utf8))",
1501 Dictionary(
1502 Box::new(Int8),
1503 Box::new(Dictionary(Box::new(Int8), Box::new(Utf8))),
1504 ),
1505 ),
1506 (
1507 r#"Struct("f1": nullable Int64, "f2": nullable Float64, "f3": nullable Timestamp(s, "+08:00"), "f4": nullable Dictionary(Int8, FixedSizeBinary(23)))"#,
1508 Struct(Fields::from(vec![
1509 Field::new("f1", Int64, true),
1510 Field::new("f2", Float64, true),
1511 Field::new("f3", Timestamp(Second, Some("+08:00".into())), true),
1512 Field::new(
1513 "f4",
1514 Dictionary(Box::new(Int8), Box::new(FixedSizeBinary(23))),
1515 true,
1516 ),
1517 ])),
1518 ),
1519 (
1520 r#"Struct("Int64": nullable Int64, "Float64": nullable Float64)"#,
1521 Struct(Fields::from(vec![
1522 Field::new("Int64", Int64, true),
1523 Field::new("Float64", Float64, true),
1524 ])),
1525 ),
1526 (
1527 r#"Struct("f1": nullable Int64, "nested_struct": nullable Struct("n1": nullable Int64))"#,
1528 Struct(Fields::from(vec![
1529 Field::new("f1", Int64, true),
1530 Field::new(
1531 "nested_struct",
1532 Struct(Fields::from(vec![Field::new("n1", Int64, true)])),
1533 true,
1534 ),
1535 ])),
1536 ),
1537 (r"Struct()", Struct(Fields::empty())),
1538 (
1539 "FixedSizeList(4, Int64)",
1540 FixedSizeList(Arc::new(Field::new_list_field(Int64, true)), 4),
1541 ),
1542 (
1543 "List(Int64)",
1544 List(Arc::new(Field::new_list_field(Int64, true))),
1545 ),
1546 (
1547 "LargeList(Int64)",
1548 LargeList(Arc::new(Field::new_list_field(Int64, true))),
1549 ),
1550 ];
1551
1552 for (data_type_string, expected_data_type) in cases {
1553 let parsed_data_type = parse_data_type(data_type_string).unwrap();
1554 assert_eq!(
1555 parsed_data_type, expected_data_type,
1556 "Parsing '{data_type_string}', expecting '{expected_data_type}'"
1557 );
1558 }
1559 }
1560
1561 #[test]
1562 fn parse_data_type_errors() {
1563 let cases = [
1565 ("", "Unsupported type ''"),
1566 ("", "Error finding next token"),
1567 ("null", "Unsupported type 'null'"),
1568 ("Nu", "Unsupported type 'Nu'"),
1569 (r"Timestamp(ns, +00:00)", "Error unknown token: +00"),
1570 (
1571 r#"Timestamp(ns, "+00:00)"#,
1572 r#"Unterminated string at: "+00:00)"#,
1573 ),
1574 (r#"Timestamp(ns, "")"#, r"empty strings aren't allowed"),
1575 (
1576 r#"Timestamp(ns, "+00:00"")"#,
1577 r#"Parser error: Unterminated string at: ")"#,
1578 ),
1579 ("Timestamp(ns, ", "Error finding next token"),
1580 (
1581 "Float32 Float32",
1582 "trailing content after parsing 'Float32'",
1583 ),
1584 ("Int32, ", "trailing content after parsing 'Int32'"),
1585 ("Int32(3), ", "trailing content after parsing 'Int32'"),
1586 (
1587 "FixedSizeBinary(Int32), ",
1588 "Error finding i64 for FixedSizeBinary, got 'Int32'",
1589 ),
1590 (
1591 "FixedSizeBinary(3.0), ",
1592 "Error parsing 3.0 as integer: invalid digit found in string",
1593 ),
1594 (
1596 "FixedSizeBinary(4000000000), ",
1597 "Error converting 4000000000 into i32 for FixedSizeBinary:",
1598 ),
1599 (
1601 "FixedSizeBinary(-1), ",
1602 "FixedSizeBinary length must be non-negative, got -1",
1603 ),
1604 (
1605 "FixedSizeList(-1, Int64), ",
1606 "FixedSizeList length must be non-negative, got -1",
1607 ),
1608 (
1610 "Decimal32(-3, 5)",
1611 "Error converting -3 into u8 for Decimal32:",
1612 ),
1613 (
1614 "Decimal64(-3, 5)",
1615 "Error converting -3 into u8 for Decimal64:",
1616 ),
1617 (
1618 "Decimal128(-3, 5)",
1619 "Error converting -3 into u8 for Decimal128:",
1620 ),
1621 (
1622 "Decimal256(-3, 5)",
1623 "Error converting -3 into u8 for Decimal256:",
1624 ),
1625 (
1626 "Decimal32(3, 500)",
1627 "Error converting 500 into i8 for Decimal32:",
1628 ),
1629 (
1630 "Decimal64(3, 500)",
1631 "Error converting 500 into i8 for Decimal64:",
1632 ),
1633 (
1634 "Decimal128(3, 500)",
1635 "Error converting 500 into i8 for Decimal128:",
1636 ),
1637 (
1638 "Decimal256(3, 500)",
1639 "Error converting 500 into i8 for Decimal256:",
1640 ),
1641 ("Struct(f1 Int64)", "Error unknown token: f1"),
1642 ("Struct(\"f1\" Int64)", "Expected ':'"),
1643 (
1644 "Struct(\"f1\": )",
1645 "Error finding next type, got unexpected ')'",
1646 ),
1647 (
1649 "Time32(µs)",
1650 "Error Time32 time unit must be 's' or 'ms', got 'µs'",
1651 ),
1652 (
1653 "Time32(ns)",
1654 "Error Time32 time unit must be 's' or 'ms', got 'ns'",
1655 ),
1656 (
1657 "Time64(s)",
1658 "Error Time64 time unit must be 'µs' or 'ns', got 's'",
1659 ),
1660 (
1661 "Time64(ms)",
1662 "Error Time64 time unit must be 'µs' or 'ns', got 'ms'",
1663 ),
1664 (
1666 "Decimal32(5, 6)",
1667 "Error Decimal32 scale '6' cannot be greater than precision '5'",
1668 ),
1669 (
1670 "Decimal64(5, 6)",
1671 "Error Decimal64 scale '6' cannot be greater than precision '5'",
1672 ),
1673 (
1674 "Decimal128(5, 6)",
1675 "Error Decimal128 scale '6' cannot be greater than precision '5'",
1676 ),
1677 (
1678 "Decimal256(5, 6)",
1679 "Error Decimal256 scale '6' cannot be greater than precision '5'",
1680 ),
1681 (
1683 "Decimal32(10, 0)",
1684 "Error Decimal32 precision must be in range [1, 9], got '10'",
1685 ),
1686 (
1687 "Decimal64(19, 0)",
1688 "Error Decimal64 precision must be in range [1, 18], got '19'",
1689 ),
1690 (
1691 "Decimal128(39, 0)",
1692 "Error Decimal128 precision must be in range [1, 38], got '39'",
1693 ),
1694 (
1695 "Decimal256(77, 0)",
1696 "Error Decimal256 precision must be in range [1, 76], got '77'",
1697 ),
1698 (
1700 "Decimal32(0, 0)",
1701 "Error Decimal32 precision must be in range [1, 9], got '0'",
1702 ),
1703 (
1704 "Decimal64(0, 0)",
1705 "Error Decimal64 precision must be in range [1, 18], got '0'",
1706 ),
1707 (
1708 "Decimal128(0, 0)",
1709 "Error Decimal128 precision must be in range [1, 38], got '0'",
1710 ),
1711 (
1712 "Decimal256(0, 0)",
1713 "Error Decimal256 precision must be in range [1, 76], got '0'",
1714 ),
1715 (
1717 r#"RunEndEncoded("re": nullable Int32, "v": non-null Utf8)"#,
1718 "RunEndEncoded run_ends field cannot be nullable",
1719 ),
1720 (
1721 r#"RunEndEncoded("re": Int32, "v": non-null Utf8)"#,
1722 "RunEndEncoded run_ends field cannot be nullable",
1723 ),
1724 (
1725 "RunEndEncoded(nullable Int32, non-null Utf8)",
1726 "RunEndEncoded run_ends field cannot be nullable",
1727 ),
1728 (
1730 r#"Map("entries": Struct("key": non-null Utf8, "value": nullable Int32), unsorted)"#,
1731 "Map entries field cannot be nullable",
1732 ),
1733 (
1735 r#"Map("entries": non-null Struct("key": nullable Utf8, "value": nullable Int32), unsorted)"#,
1736 "Map key field cannot be nullable",
1737 ),
1738 (
1739 r#"Map("entries": non-null Struct("key": Utf8, "value": nullable Int32), unsorted)"#,
1740 "Map key field cannot be nullable",
1741 ),
1742 ];
1743
1744 for (data_type_string, expected_message) in cases {
1745 println!("Parsing '{data_type_string}', expecting '{expected_message}'");
1746 match parse_data_type(data_type_string) {
1747 Ok(d) => panic!("Expected error while parsing '{data_type_string}', but got '{d}'"),
1748 Err(e) => {
1749 let message = e.to_string();
1750 assert!(
1751 message.contains(expected_message),
1752 "\n\ndid not find expected in actual.\n\nexpected: {expected_message}\nactual: {message}\n"
1753 );
1754
1755 if !message.contains("Unterminated string") {
1756 assert!(message.contains("Must be a supported arrow type name such as 'Int32' or 'Timestamp(ns)'"), "message: {message}");
1758 }
1759 }
1760 }
1761 }
1762 }
1763
1764 #[test]
1765 fn parse_error_type() {
1766 let err = parse_data_type("foobar").unwrap_err();
1767 assert!(matches!(err, ArrowError::ParseError(_)));
1768 assert_eq!(
1769 err.to_string(),
1770 "Parser error: Unsupported type 'foobar'. Must be a supported arrow type name such as 'Int32' or 'Timestamp(ns)'. Error unknown token: foobar"
1771 );
1772 }
1773}