@@ -693,11 +693,10 @@ macro_rules! generate_deser_type {
693693 } ;
694694}
695695
696- generate_deser_type ! ( deser_type_owned, ' static , |buf| types:: read_string( buf) . map( ToOwned :: to_owned) ) ;
697-
698- // This is going to be used for deserializing borrowed result metadata.
699696generate_deser_type ! ( _deser_type_borrowed, ' frame, types:: read_string) ;
700697
698+ generate_deser_type ! ( deser_type_owned, ' static , |buf| types:: read_string( buf) . map( ToOwned :: to_owned) ) ;
699+
701700/// Deserializes a table spec, be it per-column one or a global one,
702701/// in the borrowed form.
703702///
@@ -721,70 +720,114 @@ fn mk_col_spec_parse_error(
721720 }
722721}
723722
724- /// Deserializes col specs (part of ResultMetadata or PreparedMetadata)
725- /// in the owned form.
723+ /// Deserializes table spec of a column spec in the borrowed form.
726724///
727725/// Checks for equality of table specs across columns, because the protocol
728726/// does not guarantee that and we want to be sure that the assumption
729727/// of them being all the same is correct.
728+ /// To this end, the first column's table spec is written to `known_table_spec`
729+ /// and compared with remaining columns' table spec.
730730///
731- /// To avoid needless allocations, it is advised to pass `global_table_spec `
731+ /// To avoid needless allocations, it is advised to pass `known_table_spec `
732732/// in the borrowed form, so that cloning it is cheap.
733- fn deser_col_specs (
734- buf : & mut & [ u8 ] ,
735- global_table_spec : Option < TableSpec < ' _ > > ,
736- col_count : usize ,
737- ) -> StdResult < Vec < ColumnSpec < ' static > > , ColumnSpecParseError > {
738- let global_table_spec_provided = global_table_spec. is_some ( ) ;
739- let mut known_table_spec = global_table_spec;
740-
741- let mut col_specs = Vec :: with_capacity ( col_count) ;
742- for col_idx in 0 ..col_count {
743- let table_spec = match known_table_spec {
744- // If global table spec was provided, we simply clone it to each column spec.
745- Some ( ref known_spec) if global_table_spec_provided => known_spec. clone ( ) ,
746-
747- // Else, we deserialize the table spec for a column and, if we already know some
748- // previous spec (i.e. that of the first column), we perform equality check
749- // against it.
750- Some ( _) | None => {
751- let table_spec =
752- deser_table_spec ( buf) . map_err ( |err| mk_col_spec_parse_error ( col_idx, err) ) ?;
753-
754- if let Some ( ref known_spec) = known_table_spec {
755- // We assume that for each column, table spec is the same.
756- // As this is not guaranteed by the CQL protocol specification but only by how
757- // Cassandra and ScyllaDB work (no support for joins), we perform a sanity check here.
758- if known_spec. table_name != table_spec. table_name
759- || known_spec. ks_name != table_spec. ks_name
760- {
761- return Err ( mk_col_spec_parse_error (
762- col_idx,
763- ColumnSpecParseErrorKind :: TableSpecDiffersAcrossColumns (
764- known_spec. clone ( ) . into_owned ( ) ,
765- table_spec. into_owned ( ) ,
766- ) ,
767- ) ) ;
768- }
769- } else {
770- // Once we have read the first column spec, we save its table spec
771- // in order to verify its equality with other columns'.
772- known_table_spec = Some ( table_spec. clone ( ) ) ;
733+ fn deser_table_spec_for_col_spec < ' frame > (
734+ buf : & ' _ mut & ' frame [ u8 ] ,
735+ global_table_spec_provided : bool ,
736+ known_table_spec : & ' _ mut Option < TableSpec < ' frame > > ,
737+ col_idx : usize ,
738+ ) -> StdResult < TableSpec < ' frame > , ColumnSpecParseError > {
739+ let table_spec = match known_table_spec {
740+ // If global table spec was provided, we simply clone it to each column spec.
741+ Some ( ref known_spec) if global_table_spec_provided => known_spec. clone ( ) ,
742+
743+ // Else, we deserialize the table spec for a column and, if we already know some
744+ // previous spec (i.e. that of the first column), we perform equality check
745+ // against it.
746+ Some ( _) | None => {
747+ let table_spec =
748+ deser_table_spec ( buf) . map_err ( |err| mk_col_spec_parse_error ( col_idx, err) ) ?;
749+
750+ if let Some ( ref known_spec) = known_table_spec {
751+ // We assume that for each column, table spec is the same.
752+ // As this is not guaranteed by the CQL protocol specification but only by how
753+ // Cassandra and ScyllaDB work (no support for joins), we perform a sanity check here.
754+ if known_spec. table_name != table_spec. table_name
755+ || known_spec. ks_name != table_spec. ks_name
756+ {
757+ return Err ( mk_col_spec_parse_error (
758+ col_idx,
759+ ColumnSpecParseErrorKind :: TableSpecDiffersAcrossColumns (
760+ known_spec. clone ( ) . into_owned ( ) ,
761+ table_spec. into_owned ( ) ,
762+ ) ,
763+ ) ) ;
773764 }
774-
775- table_spec
765+ } else {
766+ // Once we have read the first column spec, we save its table spec
767+ // in order to verify its equality with other columns'.
768+ * known_table_spec = Some ( table_spec. clone ( ) ) ;
776769 }
777- } ;
778770
779- let name = types:: read_string ( buf)
780- . map_err ( |err| mk_col_spec_parse_error ( col_idx, err) ) ?
781- . to_owned ( ) ;
782- let typ = deser_type_owned ( buf) . map_err ( |err| mk_col_spec_parse_error ( col_idx, err) ) ?;
783- col_specs. push ( ColumnSpec :: owned ( name, typ, table_spec. into_owned ( ) ) ) ;
784- }
785- Ok ( col_specs)
771+ table_spec
772+ }
773+ } ;
774+
775+ Ok ( table_spec)
786776}
787777
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+ } ;
815+ }
816+
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+ ) ;
830+
788831fn deser_result_metadata (
789832 buf : & mut & [ u8 ] ,
790833) -> StdResult < ( ResultMetadata < ' static > , PagingStateResponse ) , ResultMetadataParseError > {
@@ -800,6 +843,7 @@ fn deser_result_metadata(
800843 let raw_paging_state = has_more_pages
801844 . then ( || types:: read_bytes ( buf) . map_err ( ResultMetadataParseError :: PagingStateParseError ) )
802845 . transpose ( ) ?;
846+
803847 let paging_state = PagingStateResponse :: new_from_raw_bytes ( raw_paging_state) ;
804848
805849 let col_specs = if no_metadata {
@@ -809,7 +853,7 @@ fn deser_result_metadata(
809853 . then ( || deser_table_spec ( buf) )
810854 . transpose ( ) ?;
811855
812- deser_col_specs ( buf, global_table_spec, col_count) ?
856+ deser_col_specs_owned ( buf, global_table_spec, col_count) ?
813857 } ;
814858
815859 let metadata = ResultMetadata {
@@ -847,7 +891,7 @@ fn deser_prepared_metadata(
847891 . then ( || deser_table_spec ( buf) )
848892 . transpose ( ) ?;
849893
850- let col_specs = deser_col_specs ( buf, global_table_spec, col_count) ?;
894+ let col_specs = deser_col_specs_owned ( buf, global_table_spec, col_count) ?;
851895
852896 Ok ( PreparedMetadata {
853897 flags,
0 commit comments