Can we make an enum serializable so it can go to and from a CqlValue (in rust)?

I am exploring how to use FromRow and SerializeCql which seems to support all of the basic types. I would like to support using enums (for example see the PersonStatus below.

Is it possible to coerce an enum to work within FromRow and SerializeCql, are there any examples anywhere?

#[derive(Debug, FromRow, SerializeCql)]
pub struct Person {
    pub uid: String,
    pub first_name: String,
    pub last_name: String,
    pub contact: Vec<Contact>,
    pub username: String,
    pub password: String,
    pub status: PersonStatus,
}

#[derive(Debug, FromUserType)]
pub enum PersonStatus {
    Unverified = 0,
    Active = 1,
    ScheduledDelete = 2,
}

#[derive(Debug, FromRow, SerializeCql)]
pub struct Contact {
    pub info: String, // email or mobile number
    pub category:ContactType,
}

What is the alternative if using enum is not possible? Would we just implement a full “deserialize struct” and “serialize struct” trait to translate and spit out the values for the scylla driver?

Looking at the driver code for how how serializing works gives me some hint that perhaps it might be possible to implement a serialization trait for the rust driver, but I’m not sure. Could an enum in the end users code go ahead and implement something like:

impl<T: SerializeCql> SerializeCql for Vec<T> {
    fn serialize<'b>(
        &self,
        typ: &ColumnType,
        writer: CellWriter<'b>,
    ) -> Result<WrittenCellProof<'b>, SerializationError> {
        // special sauce stuff
    }
}

You won’t be able to accomplish this using derive macros and I don’t see how they could be extended to work on arbitrary enums. You’ll need to do this manually.

I assume your enum won’t store any data in any variants.
First you need to decide what is the type you want to use in database for it (e.g. Int, corresponding to i32 Rust type).
Then you’ll need to write a SerializeCql and FromCqlVal<CqlValue> implementations for your enum. Those implementations can be simple and just delegate to i32 implementation.

Here’s the full example from your code. I removed ContactType field from Contact because you didn’t provide definition for it. I used num-traits and num-derive crates to convert from i32 to PersonStatus. I also derived Clone and Copy for PersonStatus to be able to cast it to i32.

use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use scylla::cql_to_rust::{FromCqlVal, FromCqlValError};
use scylla::frame::response::result::{ColumnType, CqlValue};
use scylla::macros::FromRow;
use scylla::serialize::value::SerializeCql;
use scylla::serialize::writers::WrittenCellProof;
use scylla::serialize::{CellWriter, SerializationError};
use scylla::FromUserType;

#[derive(Debug, FromRow, scylla::SerializeCql)]
pub struct Person {
    pub uid: String,
    pub first_name: String,
    pub last_name: String,
    pub contact: Vec<Contact>,
    pub username: String,
    pub password: String,
    pub status: PersonStatus,
}

#[derive(Debug, Clone, Copy, FromPrimitive)]
pub enum PersonStatus {
    Unverified = 0,
    Active = 1,
    ScheduledDelete = 2,
}

#[derive(Debug, FromUserType, scylla::SerializeCql)]
pub struct Contact {
    pub info: String, // email or mobile number
}

impl SerializeCql for PersonStatus {
    fn serialize<'b>(
        &self,
        typ: &ColumnType,
        writer: CellWriter<'b>,
    ) -> Result<WrittenCellProof<'b>, SerializationError> {
        let value = *self as i32;
        SerializeCql::serialize(&value, typ, writer)
    }
}

impl FromCqlVal<CqlValue> for PersonStatus {
    fn from_cql(cql_val: CqlValue) -> Result<Self, FromCqlValError> {
        let raw_val: Result<i32, FromCqlValError> = FromCqlVal::<CqlValue>::from_cql(cql_val);
        raw_val.and_then(|v| match FromPrimitive::from_i32(v) {
            Some(e) => Ok(e),
            None => Err(FromCqlValError::BadVal),
        })
    }
}

I opened an issue in Rust Driver to extend derive macros for your use case (enums without data): Serialization / Deserialization derive macros should work for enums without data · Issue #923 · scylladb/scylla-rust-driver · GitHub