Skip to content

Commit 8539e16

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

File tree

4 files changed

+36
-33
lines changed

4 files changed

+36
-33
lines changed

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1963,7 +1963,7 @@ fn _test_udt_bad_attributes_skip_name_check_requires_enforce_order() {}
19631963
/// ```compile_fail
19641964
///
19651965
/// #[derive(scylla_macros::DeserializeValue)]
1966-
/// #[scylla(crate = scylla_cql, enforce_order, skip_name_checks)]
1966+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
19671967
/// struct TestUdt {
19681968
/// #[scylla(rename = "b")]
19691969
/// a: i32,
@@ -1999,7 +1999,7 @@ fn _test_udt_bad_attributes_rename_collision_with_another_rename() {}
19991999
/// ```compile_fail
20002000
///
20012001
/// #[derive(scylla_macros::DeserializeValue)]
2002-
/// #[scylla(crate = scylla_cql, enforce_order, skip_name_checks)]
2002+
/// #[scylla(crate = scylla_cql, flavor = "enforce_order", skip_name_checks)]
20032003
/// struct TestUdt {
20042004
/// a: i32,
20052005
/// #[scylla(allow_missing)]

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ struct TestUdtWithNoFieldsUnordered {}
632632

633633
#[allow(unused)]
634634
#[derive(scylla_macros::DeserializeValue)]
635-
#[scylla(crate = crate, enforce_order)]
635+
#[scylla(crate = crate, flavor = "enforce_order")]
636636
struct TestUdtWithNoFieldsOrdered {}
637637

638638
#[test]
@@ -786,7 +786,7 @@ fn test_udt_loose_ordering() {
786786
#[test]
787787
fn test_udt_strict_ordering() {
788788
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
789-
#[scylla(crate = "crate", enforce_order)]
789+
#[scylla(crate = "crate", flavor = "enforce_order")]
790790
struct Udt<'a> {
791791
#[scylla(default_when_null)]
792792
a: &'a str,
@@ -860,7 +860,7 @@ fn test_udt_strict_ordering() {
860860
// An excess field at the end of UDT, when such are forbidden
861861
{
862862
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
863-
#[scylla(crate = "crate", enforce_order, forbid_excess_udt_fields)]
863+
#[scylla(crate = "crate", flavor = "enforce_order", forbid_excess_udt_fields)]
864864
struct Udt<'a> {
865865
a: &'a str,
866866
#[scylla(skip)]
@@ -934,7 +934,7 @@ fn test_udt_strict_ordering() {
934934
#[test]
935935
fn test_udt_no_name_check() {
936936
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
937-
#[scylla(crate = "crate", enforce_order, skip_name_checks)]
937+
#[scylla(crate = "crate", flavor = "enforce_order", skip_name_checks)]
938938
struct Udt<'a> {
939939
a: &'a str,
940940
#[scylla(skip)]
@@ -1762,7 +1762,7 @@ fn test_udt_errors() {
17621762
// Strict ordering
17631763
{
17641764
#[derive(scylla_macros::DeserializeValue, PartialEq, Eq, Debug)]
1765-
#[scylla(crate = "crate", enforce_order, forbid_excess_udt_fields)]
1765+
#[scylla(crate = "crate", flavor = "enforce_order", forbid_excess_udt_fields)]
17661766
struct Udt<'a> {
17671767
a: &'a str,
17681768
#[scylla(skip)]

scylla-macros/src/deserialize/value.rs

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use proc_macro::TokenStream;
55
use proc_macro2::Span;
66
use syn::{ext::IdentExt, 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 UDT. 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 UDT field names.
2422
// UDT fields will be matched to struct fields based solely on the order.
@@ -112,9 +110,10 @@ fn validate_attrs(attrs: &StructAttrs, fields: &[Field]) -> Result<(), darling::
112110

113111
if attrs.skip_name_checks {
114112
// Skipping name checks is only available in enforce_order mode
115-
if !attrs.enforce_order {
116-
let error =
117-
darling::Error::custom("attribute <skip_name_checks> requires <enforce_order>.");
113+
if attrs.flavor != Flavor::EnforceOrder {
114+
let error = darling::Error::custom(
115+
"attribute <skip_name_checks> requires <flavor = enforce_order>.",
116+
);
118117
errors.push(error);
119118
}
120119

@@ -207,18 +206,16 @@ impl StructDesc {
207206
}
208207

209208
fn generate_type_check_method(&self) -> syn::ImplItemFn {
210-
if self.attrs.enforce_order {
211-
TypeCheckAssumeOrderGenerator(self).generate()
212-
} else {
213-
TypeCheckUnorderedGenerator(self).generate()
209+
match self.attrs.flavor {
210+
Flavor::MatchByName => TypeCheckUnorderedGenerator(self).generate(),
211+
Flavor::EnforceOrder => TypeCheckAssumeOrderGenerator(self).generate(),
214212
}
215213
}
216214

217215
fn generate_deserialize_method(&self) -> syn::ImplItemFn {
218-
if self.attrs.enforce_order {
219-
DeserializeAssumeOrderGenerator(self).generate()
220-
} else {
221-
DeserializeUnorderedGenerator(self).generate()
216+
match self.attrs.flavor {
217+
Flavor::MatchByName => DeserializeUnorderedGenerator(self).generate(),
218+
Flavor::EnforceOrder => DeserializeAssumeOrderGenerator(self).generate(),
222219
}
223220
}
224221
}

scylla/src/macros.rs

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -307,20 +307,26 @@ pub use scylla_cql::macros::SerializeRow;
307307
/// macro itself, so in those cases the user must provide an alternative path
308308
/// to either the `scylla` or `scylla-cql` crate.
309309
///
310-
/// `#[scylla(enforce_order)]`
311310
///
312-
/// By default, the generated deserialization code will be insensitive
313-
/// to the UDT field order - when processing a field, it will look it up
314-
/// in the Rust struct with the corresponding field and set it. However,
315-
/// if the UDT field order is known to be the same both in the UDT
316-
/// and the Rust struct, then the `enforce_order` annotation can be used
317-
/// so that a more efficient implementation that does not perform lookups
318-
/// is be generated. The UDT field names will still be checked during the
319-
/// type check phase.
311+
/// `#[scylla(flavor = "flavor_name")]`
312+
///
313+
/// Allows to choose one of the possible "flavors", i.e. the way how the
314+
/// generated code will approach deserialization. Possible flavors are:
315+
///
316+
/// - `"match_by_name"` (default) - the generated implementation _does not
317+
/// require_ the fields in the Rust struct to be in the same order as the
318+
/// fields in the UDT. During deserialization, the implementation will take
319+
/// care to deserialize the fields in the order which the database expects.
320+
/// - `"enforce_order"` - the generated implementation _requires_ the fields
321+
/// in the Rust struct to be in the same order as the fields in the UDT.
322+
/// If the order is incorrect, type checking/deserialization will fail.
323+
/// This is a less robust flavor than `"match_by_name"`, but should be
324+
/// slightly more performant as it doesn't need to perform lookups by name.
325+
/// The UDT field names will still be checked during the type check phase.
320326
///
321327
/// #[(scylla(skip_name_checks))]
322328
///
323-
/// This attribute only works when used with `enforce_order`.
329+
/// This attribute only works when used with `flavor = "enforce_order"`.
324330
///
325331
/// If set, the generated implementation will not verify the UDT field names at
326332
/// all. Because it only works with `enforce_order`, it will deserialize first

0 commit comments

Comments
 (0)