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
Apache License 2.0
342 stars 58 forks source link

How to use cdrs blob type for serde? #332

Open makorne opened 4 years ago

makorne commented 4 years ago

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
}
AlexPikalov commented 4 years ago

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.

makorne commented 4 years ago

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 valueserializerin 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`
AlexPikalov commented 4 years ago

Like this?

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

makorne commented 4 years ago

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`
AlexPikalov commented 4 years ago

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.

makorne commented 4 years ago

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?

AlexPikalov commented 4 years ago

@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.

makorne commented 4 years ago

@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.

AlexPikalov commented 4 years ago

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.