AlexPikalov / cdrs

Cassandra DB native client written in Rust language. Find 1.x versions on https://github.com/AlexPikalov/cdrs/tree/v.1.x Looking for an async version? - Check WIP https://github.com/AlexPikalov/cdrs-async

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

How to use cdrs blob type for serde?

makorne opened this issue · comments

Hi
I am novice in Rust, and tried something like this:

use serde::{Serialize, Deserialize};

#[derive(Serialize, Deserialize, Debug, TryFromRow)]
pub struct Data {
    #[serde(with = "my_blob")]
    pub hash: Blob
}

pub mod my_blob {
    use serde::{de::Error, Deserialize, Deserializer, Serialize, Serializer};
    use std::str::FromStr;
    use cdrs::types::{blob::*, value::*};
    use cdrs::types::data_serialization_types::decode_blob;
 
    pub fn serialize<S>(val: &Blob, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
    {
        val.into_vec().serialize(serializer)
    }

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Blob, D::Error>
        where
            D: Deserializer<'de>,
    {
        let val: Vec<u8> = Deserialize::deserialize(deserializer)?;
        decode_blob(&val).map_err(D::Error::custom)
    }
}

but get the error:

val.into_vec().serialize(serializer)
   |         ^^^ move occurs because `*val` has type `cdrs::types::blob::Blob`, which does not implement the `Copy` trait
}

Hello @makorne,
You can try val.as_mut_slice().serialize(serializer). I think it should work.

However the better way (from my point of view) is to use Vec<u8> in your structures like the field hash which you presented. So, after receiving a Blog from a DB you may want to convert it into Vec<u8> and put the result into your structure.

You can try val.as_mut_slice().serialize(serializer). I think it should work.

Like this?

    pub fn deserialize<'de, D>(deserializer: D) -> Result<Blob, D::Error>
        where
            D: Deserializer<'de>,
    {
        let mut val: Vec<u8> = Deserialize::deserialize(deserializer)?;
        val.as_mut_slice().serialize(serializer);
    }

error[E0425]: cannot find value serializer in this scope

However the better way (from my point of view) is to use Vec<u8> in your structures ...

I tried Vec<u8> at the start.
But got an error:

#[derive(Serialize, Deserialize, Debug, TryFromRow)]
|                                         ^^^^^^^^^^ function or associated item not found in `u8`

Like this?

Yes. But this line val.as_mut_slice().serialize(serializer) should be in a serializer, shouldn't it?

Ha. I've been trying so long to remove error in deserializer, that was still thinking you wrote me about it some rust kung-fu :)
Yes. But changing does not solve the problem.

    pub fn serialize<S>(val: &mut Blob, serializer: S) -> Result<S::Ok, S::Error>
        where
            S: Serializer,
    {
        val.as_mut_slice().serialize(serializer)
    }
 #[derive(Serialize, Deserialize, Debug, TryFromRow)]
   |          ^^^^^^^^^ types differ in mutability
   |
   = note: expected mutable reference `&mut cdrs::types::blob::Blob`
                      found reference `&'__a cdrs::types::blob::Blob`

I think you can simplify your life a bit by omitting manual implementation. There is something from Serde team that helps to work with byte arrays. https://github.com/serde-rs/bytes
Blob is a Cassandra type that represents a byte array.

So, what you could do is following:

As I said, I recommend to not use Blob in your domain data structures and prefer Rust-based types instead of ones from Cassandra domain. For such Rust-based types I'll have more support in libs like Serde and you'll have less manual work. In this case, it means to use Vec<u8> instead of Blob.

But as I wrote before, Vec<u8> was throwing cdrs errors:

54 | #[derive(Serialize, Deserialize, Debug, TryFromRow)]
   |                                         ^^^^^^^^^^ function or associated item not found in `u8`
error[E0599]: no function or associated item named `try_from_udt` found for type `u8` in the current scope

What to do with this?
Remove TryFromRow from #[derive(Serialize, Deserialize, Debug, TryFromRow)],
and not use ::try_from_row(row)? And do its work manually?

@makorne
Please let me check how TryFromRow works in case if some field is a blob (vector of bytes). I'll get back to you in this issue.

@AlexPikalov
Hi, I hope you are ok in our pandemic time?

Any news about blob issue?

Please let me check how TryFromRow works in case if some field is a blob (vector of bytes). I'll get back to you in this issue.

Hi @makorne ,
Sorry for quite a late response. The problem cause is in the proc macro that derives TryFromRow trait. Unfortunately, I was not able to start the work on it.