Skip to content

Commit 66b0172

Browse files
committed
macros: DeserializeRow uses Flavor
Instead of taking `enforce_order` as boolean flag, DeserializeRow now takes a string (e.g., `flavor = "enforce_order"`) and converts it to a variant of the Flavor enum. This way DeserializeRow is unified with SerializeRow wrt flavor selection.
1 parent 8539e16 commit 66b0172

File tree

3 files changed

+29
-27
lines changed

3 files changed

+29
-27
lines changed

scylla-cql/src/types/deserialize/row_tests.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct TestUdtWithNoFieldsUnordered {}
9191

9292
#[allow(unused)]
9393
#[derive(DeserializeRow)]
94-
#[scylla(crate = crate, enforce_order)]
94+
#[scylla(crate = crate, flavor = "enforce_order")]
9595
struct TestUdtWithNoFieldsOrdered {}
9696

9797
#[test]
@@ -143,7 +143,7 @@ fn test_struct_deserialization_loose_ordering() {
143143
#[test]
144144
fn test_struct_deserialization_strict_ordering() {
145145
#[derive(DeserializeRow, PartialEq, Eq, Debug)]
146-
#[scylla(crate = "crate", enforce_order)]
146+
#[scylla(crate = "crate", flavor = "enforce_order")]
147147
struct MyRow<'a> {
148148
a: &'a str,
149149
b: Option<i32>,
@@ -180,7 +180,7 @@ fn test_struct_deserialization_strict_ordering() {
180180
#[test]
181181
fn test_struct_deserialization_no_name_check() {
182182
#[derive(DeserializeRow, PartialEq, Eq, Debug)]
183-
#[scylla(crate = "crate", enforce_order, skip_name_checks)]
183+
#[scylla(crate = "crate", flavor = "enforce_order", skip_name_checks)]
184184
struct MyRow<'a> {
185185
a: &'a str,
186186
b: Option<i32>,
@@ -623,7 +623,7 @@ fn test_struct_deserialization_errors() {
623623
// Strict ordering
624624
{
625625
#[derive(scylla_macros::DeserializeRow, PartialEq, Eq, Debug)]
626-
#[scylla(crate = "crate", enforce_order)]
626+
#[scylla(crate = "crate", flavor = "enforce_order")]
627627
struct MyRow<'a> {
628628
a: &'a str,
629629
#[scylla(skip)]

scylla-macros/src/deserialize/row.rs

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use proc_macro2::Span;
55
use syn::ext::IdentExt;
66
use syn::parse_quote;
77

8+
use crate::Flavor;
9+
810
use super::{DeserializeCommonFieldAttrs, DeserializeCommonStructAttrs};
911

1012
#[derive(FromAttributes)]
@@ -13,12 +15,8 @@ struct StructAttrs {
1315
#[darling(rename = "crate")]
1416
crate_path: Option<syn::Path>,
1517

16-
// If true, then the type checking code will require the order of the fields
17-
// to be the same in both the Rust struct and the columns. This allows the
18-
// deserialization to be slightly faster because looking struct fields up
19-
// by name can be avoided, though it is less convenient.
2018
#[darling(default)]
21-
enforce_order: bool,
19+
flavor: Flavor,
2220

2321
// If true, then the type checking code won't verify the column names.
2422
// Columns will be matched to struct fields based solely on the order.
@@ -94,7 +92,7 @@ fn validate_attrs(attrs: &StructAttrs, fields: &[Field]) -> Result<(), darling::
9492

9593
if attrs.skip_name_checks {
9694
// Skipping name checks is only available in enforce_order mode
97-
if !attrs.enforce_order {
95+
if attrs.flavor != Flavor::EnforceOrder {
9896
let error =
9997
darling::Error::custom("attribute <skip_name_checks> requires <enforce_order>.");
10098
errors.push(error);
@@ -153,18 +151,16 @@ type StructDesc = super::StructDescForDeserialize<StructAttrs, Field>;
153151

154152
impl StructDesc {
155153
fn generate_type_check_method(&self) -> syn::ImplItemFn {
156-
if self.attrs.enforce_order {
157-
TypeCheckAssumeOrderGenerator(self).generate()
158-
} else {
159-
TypeCheckUnorderedGenerator(self).generate()
154+
match self.attrs.flavor {
155+
Flavor::MatchByName => TypeCheckUnorderedGenerator(self).generate(),
156+
Flavor::EnforceOrder => TypeCheckAssumeOrderGenerator(self).generate(),
160157
}
161158
}
162159

163160
fn generate_deserialize_method(&self) -> syn::ImplItemFn {
164-
if self.attrs.enforce_order {
165-
DeserializeAssumeOrderGenerator(self).generate()
166-
} else {
167-
DeserializeUnorderedGenerator(self).generate()
161+
match self.attrs.flavor {
162+
Flavor::MatchByName => DeserializeUnorderedGenerator(self).generate(),
163+
Flavor::EnforceOrder => DeserializeAssumeOrderGenerator(self).generate(),
168164
}
169165
}
170166
}

scylla/src/macros.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -443,19 +443,25 @@ pub use scylla_macros::DeserializeValue;
443443
/// macro itself, so in those cases the user must provide an alternative path
444444
/// to either the `scylla` or `scylla-cql` crate.
445445
///
446-
/// `#[scylla(enforce_order)]`
446+
/// `#[scylla(flavor = "flavor_name")]`
447447
///
448-
/// By default, the generated deserialization code will be insensitive
449-
/// to the column order - when processing a column, the corresponding Rust field
450-
/// will be looked up and the column will be deserialized based on its type.
451-
/// However, if the column order and the Rust field order is known to be the
452-
/// same, then the `enforce_order` annotation can be used so that a more
453-
/// efficient implementation that does not perform lookups is be generated.
454-
/// The generated code will still check that the column and field names match.
448+
/// Allows to choose one of the possible "flavors", i.e. the way how the
449+
/// generated code will approach deserialization. Possible flavors are:
450+
///
451+
/// - `"match_by_name"` (default) - the generated implementation _does not
452+
/// require_ the fields in the Rust struct to be in the same order as the
453+
/// columns in the row. During deserialization, the implementation will take
454+
/// care to deserialize the columns in the order which the database provided.
455+
/// - `"enforce_order"` - the generated implementation _requires_ the fields
456+
/// in the Rust struct to be in the same order as the columns in the row.
457+
/// If the order is incorrect, type checking/deserialization will fail.
458+
/// This is a less robust flavor than `"match_by_name"`, but should be
459+
/// slightly more performant as it doesn't need to perform lookups by name.
460+
/// The generated code will still check that the column and field names match.
455461
///
456462
/// #[(scylla(skip_name_checks))]
457463
///
458-
/// This attribute only works when used with `enforce_order`.
464+
/// This attribute only works when used with `flavor = "enforce_order"`.
459465
///
460466
/// If set, the generated implementation will not verify the column names at
461467
/// all. Because it only works with `enforce_order`, it will deserialize first

0 commit comments

Comments
 (0)