|
1 | 1 | use crate::cql_to_rust::{FromRow, FromRowError}; |
2 | 2 | use crate::frame::frame_errors::{ |
3 | 3 | ColumnSpecParseError, ColumnSpecParseErrorKind, CqlResultParseError, CqlTypeParseError, |
4 | | - PreparedParseError, ResultMetadataParseError, RowsParseError, SchemaChangeEventParseError, |
5 | | - SetKeyspaceParseError, TableSpecParseError, |
| 4 | + LowLevelDeserializationError, PreparedParseError, ResultMetadataParseError, RowsParseError, |
| 5 | + SchemaChangeEventParseError, SetKeyspaceParseError, TableSpecParseError, |
6 | 6 | }; |
7 | 7 | use crate::frame::request::query::PagingStateResponse; |
8 | 8 | use crate::frame::response::event::SchemaChangeEvent; |
@@ -603,99 +603,104 @@ pub enum Result { |
603 | 603 | SchemaChange(SchemaChange), |
604 | 604 | } |
605 | 605 |
|
606 | | -macro_rules! generate_deser_type { |
607 | | - ($deser_type: ident, $l: lifetime, $read_string: expr) => { |
608 | | - fn $deser_type<'frame>( |
609 | | - buf: &mut &'frame [u8], |
610 | | - ) -> StdResult<ColumnType<$l>, CqlTypeParseError> { |
611 | | - use ColumnType::*; |
612 | | - let id = types::read_short(buf) |
613 | | - .map_err(|err| CqlTypeParseError::TypeIdParseError(err.into()))?; |
614 | | - Ok(match id { |
615 | | - 0x0000 => { |
616 | | - // We use types::read_string instead of $read_string here on purpose. |
617 | | - // Chances are the underlying string is `...DurationType`, in which case |
618 | | - // we don't need to allocate it at all. Only for Custom types |
619 | | - // (which we don't support anyway) do we need to allocate. |
620 | | - // OTOH, the macro argument function deserializes borrowed OR owned string; |
621 | | - // here we want to always deserialize borrowed string. |
622 | | - let type_str = types::read_string(buf) |
623 | | - .map_err(CqlTypeParseError::CustomTypeNameParseError)?; |
624 | | - match type_str { |
625 | | - "org.apache.cassandra.db.marshal.DurationType" => Duration, |
626 | | - _ => Custom(type_str.to_owned().into()), |
627 | | - } |
628 | | - } |
629 | | - 0x0001 => Ascii, |
630 | | - 0x0002 => BigInt, |
631 | | - 0x0003 => Blob, |
632 | | - 0x0004 => Boolean, |
633 | | - 0x0005 => Counter, |
634 | | - 0x0006 => Decimal, |
635 | | - 0x0007 => Double, |
636 | | - 0x0008 => Float, |
637 | | - 0x0009 => Int, |
638 | | - 0x000B => Timestamp, |
639 | | - 0x000C => Uuid, |
640 | | - 0x000D => Text, |
641 | | - 0x000E => Varint, |
642 | | - 0x000F => Timeuuid, |
643 | | - 0x0010 => Inet, |
644 | | - 0x0011 => Date, |
645 | | - 0x0012 => Time, |
646 | | - 0x0013 => SmallInt, |
647 | | - 0x0014 => TinyInt, |
648 | | - 0x0015 => Duration, |
649 | | - 0x0020 => List(Box::new($deser_type(buf)?)), |
650 | | - 0x0021 => Map(Box::new($deser_type(buf)?), Box::new($deser_type(buf)?)), |
651 | | - 0x0022 => Set(Box::new($deser_type(buf)?)), |
652 | | - 0x0030 => { |
653 | | - let keyspace_name = |
654 | | - $read_string(buf).map_err(CqlTypeParseError::UdtKeyspaceNameParseError)?; |
655 | | - let type_name = |
656 | | - $read_string(buf).map_err(CqlTypeParseError::UdtNameParseError)?; |
657 | | - let fields_size: usize = types::read_short(buf) |
658 | | - .map_err(|err| CqlTypeParseError::UdtFieldsCountParseError(err.into()))? |
659 | | - .into(); |
660 | | - |
661 | | - let mut field_types: Vec<(Cow<$l, str>, ColumnType)> = |
662 | | - Vec::with_capacity(fields_size); |
663 | | - |
664 | | - for _ in 0..fields_size { |
665 | | - let field_name = |
666 | | - $read_string(buf).map_err(CqlTypeParseError::UdtFieldNameParseError)?; |
667 | | - let field_type = $deser_type(buf)?; |
668 | | - |
669 | | - field_types.push((field_name.into(), field_type)); |
670 | | - } |
671 | | - |
672 | | - UserDefinedType { |
673 | | - type_name: type_name.into(), |
674 | | - keyspace: keyspace_name.into(), |
675 | | - field_types, |
676 | | - } |
677 | | - } |
678 | | - 0x0031 => { |
679 | | - let len: usize = types::read_short(buf) |
680 | | - .map_err(|err| CqlTypeParseError::TupleLengthParseError(err.into()))? |
681 | | - .into(); |
682 | | - let mut types = Vec::with_capacity(len); |
683 | | - for _ in 0..len { |
684 | | - types.push($deser_type(buf)?); |
685 | | - } |
686 | | - Tuple(types) |
687 | | - } |
688 | | - id => { |
689 | | - return Err(CqlTypeParseError::TypeNotImplemented(id)); |
690 | | - } |
691 | | - }) |
| 606 | +fn deser_type_generic<'frame, 'result, StrT: Into<Cow<'result, str>>>( |
| 607 | + buf: &mut &'frame [u8], |
| 608 | + read_string: fn(&mut &'frame [u8]) -> StdResult<StrT, LowLevelDeserializationError>, |
| 609 | +) -> StdResult<ColumnType<'result>, CqlTypeParseError> { |
| 610 | + use ColumnType::*; |
| 611 | + let id = |
| 612 | + types::read_short(buf).map_err(|err| CqlTypeParseError::TypeIdParseError(err.into()))?; |
| 613 | + Ok(match id { |
| 614 | + 0x0000 => { |
| 615 | + // We use types::read_string instead of read_string argument here on purpose. |
| 616 | + // Chances are the underlying string is `...DurationType`, in which case |
| 617 | + // we don't need to allocate it at all. Only for Custom types |
| 618 | + // (which we don't support anyway) do we need to allocate. |
| 619 | + // OTOH, the macro argument function deserializes borrowed OR owned string; |
| 620 | + // here we want to always deserialize borrowed string. |
| 621 | + let type_str = |
| 622 | + types::read_string(buf).map_err(CqlTypeParseError::CustomTypeNameParseError)?; |
| 623 | + match type_str { |
| 624 | + "org.apache.cassandra.db.marshal.DurationType" => Duration, |
| 625 | + _ => Custom(type_str.to_owned().into()), |
| 626 | + } |
692 | 627 | } |
693 | | - }; |
| 628 | + 0x0001 => Ascii, |
| 629 | + 0x0002 => BigInt, |
| 630 | + 0x0003 => Blob, |
| 631 | + 0x0004 => Boolean, |
| 632 | + 0x0005 => Counter, |
| 633 | + 0x0006 => Decimal, |
| 634 | + 0x0007 => Double, |
| 635 | + 0x0008 => Float, |
| 636 | + 0x0009 => Int, |
| 637 | + 0x000B => Timestamp, |
| 638 | + 0x000C => Uuid, |
| 639 | + 0x000D => Text, |
| 640 | + 0x000E => Varint, |
| 641 | + 0x000F => Timeuuid, |
| 642 | + 0x0010 => Inet, |
| 643 | + 0x0011 => Date, |
| 644 | + 0x0012 => Time, |
| 645 | + 0x0013 => SmallInt, |
| 646 | + 0x0014 => TinyInt, |
| 647 | + 0x0015 => Duration, |
| 648 | + 0x0020 => List(Box::new(deser_type_generic(buf, read_string)?)), |
| 649 | + 0x0021 => Map( |
| 650 | + Box::new(deser_type_generic(buf, read_string)?), |
| 651 | + Box::new(deser_type_generic(buf, read_string)?), |
| 652 | + ), |
| 653 | + 0x0022 => Set(Box::new(deser_type_generic(buf, read_string)?)), |
| 654 | + 0x0030 => { |
| 655 | + let keyspace_name = |
| 656 | + read_string(buf).map_err(CqlTypeParseError::UdtKeyspaceNameParseError)?; |
| 657 | + let type_name = read_string(buf).map_err(CqlTypeParseError::UdtNameParseError)?; |
| 658 | + let fields_size: usize = types::read_short(buf) |
| 659 | + .map_err(|err| CqlTypeParseError::UdtFieldsCountParseError(err.into()))? |
| 660 | + .into(); |
| 661 | + |
| 662 | + let mut field_types: Vec<(Cow<'result, str>, ColumnType)> = |
| 663 | + Vec::with_capacity(fields_size); |
| 664 | + |
| 665 | + for _ in 0..fields_size { |
| 666 | + let field_name = |
| 667 | + read_string(buf).map_err(CqlTypeParseError::UdtFieldNameParseError)?; |
| 668 | + let field_type = deser_type_generic(buf, read_string)?; |
| 669 | + |
| 670 | + field_types.push((field_name.into(), field_type)); |
| 671 | + } |
| 672 | + |
| 673 | + UserDefinedType { |
| 674 | + type_name: type_name.into(), |
| 675 | + keyspace: keyspace_name.into(), |
| 676 | + field_types, |
| 677 | + } |
| 678 | + } |
| 679 | + 0x0031 => { |
| 680 | + let len: usize = types::read_short(buf) |
| 681 | + .map_err(|err| CqlTypeParseError::TupleLengthParseError(err.into()))? |
| 682 | + .into(); |
| 683 | + let mut types = Vec::with_capacity(len); |
| 684 | + for _ in 0..len { |
| 685 | + types.push(deser_type_generic(buf, read_string)?); |
| 686 | + } |
| 687 | + Tuple(types) |
| 688 | + } |
| 689 | + id => { |
| 690 | + return Err(CqlTypeParseError::TypeNotImplemented(id)); |
| 691 | + } |
| 692 | + }) |
694 | 693 | } |
695 | 694 |
|
696 | | -generate_deser_type!(_deser_type_borrowed, 'frame, types::read_string); |
| 695 | +fn _deser_type_borrowed<'frame>( |
| 696 | + buf: &mut &'frame [u8], |
| 697 | +) -> StdResult<ColumnType<'frame>, CqlTypeParseError> { |
| 698 | + deser_type_generic(buf, |buf| types::read_string(buf)) |
| 699 | +} |
697 | 700 |
|
698 | | -generate_deser_type!(deser_type_owned, 'static, |buf| types::read_string(buf).map(ToOwned::to_owned)); |
| 701 | +fn deser_type_owned(buf: &mut &[u8]) -> StdResult<ColumnType<'static>, CqlTypeParseError> { |
| 702 | + deser_type_generic(buf, |buf| types::read_string(buf).map(ToOwned::to_owned)) |
| 703 | +} |
699 | 704 |
|
700 | 705 | /// Deserializes a table spec, be it per-column one or a global one, |
701 | 706 | /// in the borrowed form. |
|
0 commit comments