@@ -14,19 +14,20 @@ pub(crate) fn from_row_derive(tokens_input: TokenStream) -> Result<TokenStream,
14
14
// Generates a token that sets the values of struct fields: field_type::from_cql(...)
15
15
let ( fill_struct_code, fields_count) = match struct_fields {
16
16
crate :: parser:: StructFields :: Named ( fields) => {
17
- let set_fields_code = fields. named . iter ( ) . map ( |field| {
17
+ let set_fields_code = fields. named . iter ( ) . enumerate ( ) . map ( |( col_ix , field) | {
18
18
let field_name = & field. ident ;
19
19
let field_type = & field. ty ;
20
20
21
21
quote_spanned ! { field. span( ) =>
22
22
#field_name: {
23
- let ( col_ix, col_value) = vals_iter
24
- . next( )
25
- . expect( "BUG: Size validated iterator did not contain the expected number of values" ) ;
23
+ // To avoid unnecessary copy `std::mem::take` is used.
24
+ // Using explicit indexing operation is safe because `row_columns` is an array and `col_ix` is a litteral.
25
+ // <https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/builtin/static.UNCONDITIONAL_PANIC.html>
26
+ let col_value = :: std:: mem:: take( & mut row_columns[ #col_ix] ) ;
26
27
<#field_type as FromCqlVal <:: std:: option:: Option <CqlValue >>>:: from_cql( col_value)
27
28
. map_err( |e| FromRowError :: BadCqlVal {
28
29
err: e,
29
- column: col_ix,
30
+ column: # col_ix,
30
31
} ) ?
31
32
} ,
32
33
}
@@ -39,19 +40,19 @@ pub(crate) fn from_row_derive(tokens_input: TokenStream) -> Result<TokenStream,
39
40
( fill_struct_code, fields. named . len ( ) )
40
41
}
41
42
crate :: parser:: StructFields :: Unnamed ( fields) => {
42
- let set_fields_code = fields. unnamed . iter ( ) . map ( |field| {
43
+ let set_fields_code = fields. unnamed . iter ( ) . enumerate ( ) . map ( |( col_ix , field) | {
43
44
let field_type = & field. ty ;
44
45
45
46
quote_spanned ! { field. span( ) =>
46
47
{
47
- let ( col_ix , col_value ) = vals_iter
48
- . next ( )
49
- . expect ( "BUG: Size validated iterator did not contain the expected number of values" ) ;
50
-
48
+ // To avoid unnecessary copy `std::mem::take` is used.
49
+ // Using explicit indexing operation is safe because `row_columns` is an array and `col_ix` is a litteral.
50
+ // <https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/builtin/static.UNCONDITIONAL_PANIC.html>
51
+ let col_value = :: std :: mem :: take ( & mut row_columns [ #col_ix ] ) ;
51
52
<#field_type as FromCqlVal <:: std:: option:: Option <CqlValue >>>:: from_cql( col_value)
52
53
. map_err( |e| FromRowError :: BadCqlVal {
53
54
err: e,
54
- column: col_ix,
55
+ column: # col_ix,
55
56
} ) ?
56
57
} ,
57
58
}
@@ -71,15 +72,17 @@ pub(crate) fn from_row_derive(tokens_input: TokenStream) -> Result<TokenStream,
71
72
-> :: std:: result:: Result <Self , #path:: FromRowError > {
72
73
use #path:: { CqlValue , FromCqlVal , FromRow , FromRowError } ;
73
74
use :: std:: result:: Result :: { Ok , Err } ;
75
+ use :: std:: convert:: TryInto ;
74
76
use :: std:: iter:: { Iterator , IntoIterator } ;
75
77
76
- if #fields_count != row. columns. len( ) {
77
- return Err ( FromRowError :: WrongRowSize {
78
- expected: #fields_count,
79
- actual: row. columns. len( ) ,
80
- } ) ;
81
- }
82
- let mut vals_iter = row. columns. into_iter( ) . enumerate( ) ;
78
+
79
+ let row_columns_len = row. columns. len( ) ;
80
+ // An array used, to enable [uncoditional paniking](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/builtin/static.UNCONDITIONAL_PANIC.html)
81
+ // for "index out of range" issues and be able to catch them during the compile time.
82
+ let mut row_columns: [ _; #fields_count] = row. columns. try_into( ) . map_err( |_| FromRowError :: WrongRowSize {
83
+ expected: #fields_count,
84
+ actual: row_columns_len,
85
+ } ) ?;
83
86
84
87
Ok ( #struct_name #fill_struct_code)
85
88
}
0 commit comments