|
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. |
@@ -775,58 +780,73 @@ fn deser_table_spec_for_col_spec<'frame>( |
775 | 780 | Ok(table_spec) |
776 | 781 | } |
777 | 782 |
|
778 | | -macro_rules! generate_deser_col_specs { |
779 | | - ($deser_col_specs: ident, $l: lifetime, $deser_type: ident, $make_col_spec: expr $(,)?) => { |
780 | | - /// Deserializes col specs (part of ResultMetadata or PreparedMetadata) |
781 | | - /// in the form mentioned by its name. |
782 | | - /// |
783 | | - /// Checks for equality of table specs across columns, because the protocol |
784 | | - /// does not guarantee that and we want to be sure that the assumption |
785 | | - /// of them being all the same is correct. |
786 | | - /// |
787 | | - /// To avoid needless allocations, it is advised to pass `global_table_spec` |
788 | | - /// in the borrowed form, so that cloning it is cheap. |
789 | | - fn $deser_col_specs<'frame>( |
790 | | - buf: &mut &'frame [u8], |
791 | | - global_table_spec: Option<TableSpec<'frame>>, |
792 | | - col_count: usize, |
793 | | - ) -> StdResult<Vec<ColumnSpec<$l>>, ColumnSpecParseError> { |
794 | | - let global_table_spec_provided = global_table_spec.is_some(); |
795 | | - let mut known_table_spec = global_table_spec; |
796 | | - |
797 | | - let mut col_specs = Vec::with_capacity(col_count); |
798 | | - for col_idx in 0..col_count { |
799 | | - let table_spec = deser_table_spec_for_col_spec( |
800 | | - buf, |
801 | | - global_table_spec_provided, |
802 | | - &mut known_table_spec, |
803 | | - col_idx, |
804 | | - )?; |
805 | | - |
806 | | - let name = |
807 | | - types::read_string(buf).map_err(|err| mk_col_spec_parse_error(col_idx, err))?; |
808 | | - let typ = $deser_type(buf).map_err(|err| mk_col_spec_parse_error(col_idx, err))?; |
809 | | - let col_spec = $make_col_spec(name, typ, table_spec); |
810 | | - col_specs.push(col_spec); |
811 | | - } |
812 | | - Ok(col_specs) |
813 | | - } |
814 | | - }; |
| 783 | +/// Deserializes col specs (part of ResultMetadata or PreparedMetadata) |
| 784 | +/// in the form mentioned by its name. |
| 785 | +/// |
| 786 | +/// Checks for equality of table specs across columns, because the protocol |
| 787 | +/// does not guarantee that and we want to be sure that the assumption |
| 788 | +/// of them being all the same is correct. |
| 789 | +/// |
| 790 | +/// To avoid needless allocations, it is advised to pass `global_table_spec` |
| 791 | +/// in the borrowed form, so that cloning it is cheap. |
| 792 | +fn deser_col_specs_generic<'frame, 'result>( |
| 793 | + buf: &mut &'frame [u8], |
| 794 | + global_table_spec: Option<TableSpec<'frame>>, |
| 795 | + col_count: usize, |
| 796 | + make_col_spec: fn(&'frame str, ColumnType<'result>, TableSpec<'frame>) -> ColumnSpec<'result>, |
| 797 | + deser_type: fn(&mut &'frame [u8]) -> StdResult<ColumnType<'result>, CqlTypeParseError>, |
| 798 | +) -> StdResult<Vec<ColumnSpec<'result>>, ColumnSpecParseError> { |
| 799 | + let global_table_spec_provided = global_table_spec.is_some(); |
| 800 | + let mut known_table_spec = global_table_spec; |
| 801 | + |
| 802 | + let mut col_specs = Vec::with_capacity(col_count); |
| 803 | + for col_idx in 0..col_count { |
| 804 | + let table_spec = deser_table_spec_for_col_spec( |
| 805 | + buf, |
| 806 | + global_table_spec_provided, |
| 807 | + &mut known_table_spec, |
| 808 | + col_idx, |
| 809 | + )?; |
| 810 | + |
| 811 | + let name = types::read_string(buf).map_err(|err| mk_col_spec_parse_error(col_idx, err))?; |
| 812 | + let typ = deser_type(buf).map_err(|err| mk_col_spec_parse_error(col_idx, err))?; |
| 813 | + let col_spec = make_col_spec(name, typ, table_spec); |
| 814 | + col_specs.push(col_spec); |
| 815 | + } |
| 816 | + Ok(col_specs) |
| 817 | +} |
| 818 | + |
| 819 | +fn _deser_col_specs_borrowed<'frame>( |
| 820 | + buf: &mut &'frame [u8], |
| 821 | + global_table_spec: Option<TableSpec<'frame>>, |
| 822 | + col_count: usize, |
| 823 | +) -> StdResult<Vec<ColumnSpec<'frame>>, ColumnSpecParseError> { |
| 824 | + deser_col_specs_generic( |
| 825 | + buf, |
| 826 | + global_table_spec, |
| 827 | + col_count, |
| 828 | + ColumnSpec::borrowed, |
| 829 | + _deser_type_borrowed, |
| 830 | + ) |
815 | 831 | } |
816 | 832 |
|
817 | | -generate_deser_col_specs!( |
818 | | - _deser_col_specs_borrowed, |
819 | | - 'frame, |
820 | | - _deser_type_borrowed, |
821 | | - ColumnSpec::borrowed, |
822 | | -); |
823 | | - |
824 | | -generate_deser_col_specs!( |
825 | | - deser_col_specs_owned, |
826 | | - 'static, |
827 | | - deser_type_owned, |
828 | | - |name: &str, typ, table_spec: TableSpec| ColumnSpec::owned(name.to_owned(), typ, table_spec.into_owned()), |
829 | | -); |
| 833 | +fn deser_col_specs_owned<'frame>( |
| 834 | + buf: &mut &'frame [u8], |
| 835 | + global_table_spec: Option<TableSpec<'frame>>, |
| 836 | + col_count: usize, |
| 837 | +) -> StdResult<Vec<ColumnSpec<'static>>, ColumnSpecParseError> { |
| 838 | + let result: StdResult<Vec<ColumnSpec<'static>>, ColumnSpecParseError> = deser_col_specs_generic( |
| 839 | + buf, |
| 840 | + global_table_spec, |
| 841 | + col_count, |
| 842 | + |name: &str, typ, table_spec: TableSpec| { |
| 843 | + ColumnSpec::owned(name.to_owned(), typ, table_spec.into_owned()) |
| 844 | + }, |
| 845 | + deser_type_owned, |
| 846 | + ); |
| 847 | + |
| 848 | + result |
| 849 | +} |
830 | 850 |
|
831 | 851 | fn deser_result_metadata( |
832 | 852 | buf: &mut &[u8], |
|
0 commit comments