Derive Macro scylla::DeserializeValue

source ·
#[derive(DeserializeValue)]
{
    // Attributes available to this derive:
    #[scylla]
}
Expand description

Derive macro for the DeserializeValue trait that generates an implementation which deserializes a User Defined Type with the same layout as the Rust struct.

At the moment, only structs with named fields are supported.

This macro properly supports structs with lifetimes, meaning that you can deserialize UDTs with fields that borrow memory from the serialized response.

§Example

A UDT defined like this:

CREATE TYPE ks.my_udt (a i32, b text, c blob);

…can be deserialized using the following struct:

#[derive(DeserializeValue)]
struct MyUdt<'a> {
    a: i32,
    b: Option<String>,
    c: &'a [u8],
}

§Attributes

The macro supports a number of attributes that customize the generated implementation. Many of the attributes were inspired by procedural macros from serde and try to follow the same naming conventions.

§Struct attributes

#[scylla(crate = "crate_name")]

By default, the code generated by the derive macro will refer to the items defined by the driver (types, traits, etc.) via the ::scylla path. For example, it will refer to the DeserializeValue trait using the following path:

use ::scylla::_macro_internal::DeserializeValue;

Most users will simply add scylla to their dependencies, then use the derive macro and the path above will work. However, there are some niche cases where this path will not work:

  • The scylla crate is imported under a different name,
  • The scylla crate is not imported at all - the macro actually is defined in the scylla-macros crate and the generated code depends on items defined in scylla-cql.

It’s not possible to automatically resolve those issues in the procedural macro itself, so in those cases the user must provide an alternative path to either the scylla or scylla-cql crate.

#[scylla(flavor = "flavor_name")]

Allows to choose one of the possible “flavors”, i.e. the way how the generated code will approach deserialization. Possible flavors are:

  • "match_by_name" (default) - the generated implementation does not require the fields in the Rust struct to be in the same order as the fields in the UDT. During deserialization, the implementation will take care to deserialize the fields in the order which the database expects.
  • "enforce_order" - the generated implementation requires the fields in the Rust struct to be in the same order as the fields in the UDT. If the order is incorrect, type checking/deserialization will fail. This is a less robust flavor than "match_by_name", but should be slightly more performant as it doesn’t need to perform lookups by name. The UDT field names will still be checked during the type check phase.

#[(scylla(skip_name_checks))]

This attribute only works when used with flavor = "enforce_order".

If set, the generated implementation will not verify the UDT field names at all. Because it only works with enforce_order, it will deserialize first UDT field into the first struct field, second UDT field into the second struct field and so on. It will still verify that the UDT field types and struct field types match.

#[(scylla(forbid_excess_udt_fields))]

By default, the generated deserialization code ignores excess UDT fields. I.e., enforce_order flavour ignores excess UDT fields in the suffix of the UDT definition, and the default unordered flavour ignores excess UDT fields anywhere. If more strictness is desired, this flag makes sure that no excess fields are present and forces error in case there are some.

§Field attributes

#[scylla(skip)]

The field will be completely ignored during deserialization and will be initialized with Default::default().

#[scylla(allow_missing)]

If the UDT definition does not contain this field, it will be initialized with Default::default().

#[scylla(default_when_null)]

If the value of the field received from DB is null, the field will be initialized with Default::default().

#[scylla(rename = "field_name")]

By default, the generated implementation will try to match the Rust field to a UDT field with the same name. This attribute instead allows to match to a UDT field with provided name.