1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
/// Generate `From` and `Into` for your prost message.
///
/// When you use it, plese include `use prost::Message;` in your code.
/// Note both `$type` and `&$type` will be generated.
#[macro_export]
macro_rules! prost_into_vec {
    ($(($type:ty, $cap:expr)),*) => {
        $(impl std::convert::From<$type> for Vec<u8> {
            fn from(msg: $type) -> Self {
                let mut buf = bytes::BytesMut::with_capacity($cap);
                msg.encode(&mut buf).unwrap();
                buf.to_vec()
            }
        }
        impl std::convert::From<&$type> for Vec<u8> {
            fn from(msg: &$type) -> Self {
                let mut buf = bytes::BytesMut::with_capacity($cap);
                msg.encode(&mut buf).unwrap();
                buf.to_vec()
            }
        })*
    };
}

/// Generate `TryFrom` and `TryInto` for your prost message from `Vec<u8>`.
///
/// When you use it, plese include `use prost::Message;` in your code.
/// Please remember to `use std::convert::TryInto;` when you want to use generated functions.
#[macro_export]
macro_rules! vec_try_into_prost {
    ($($type:ty),*) => {
        $(impl std::convert::TryFrom<Vec<u8>> for $type {
            type Error = prost::DecodeError;
            fn try_from(buf: Vec<u8>) -> Result<Self, Self::Error> {
                let msg: $type = Message::decode(&buf[..])?;
                Ok(msg)
            }
        }

        impl std::convert::TryFrom<&[u8]> for $type {
            type Error = prost::DecodeError;
            fn try_from(buf: &[u8]) -> Result<Self, Self::Error> {
                let msg: $type = Message::decode(buf)?;
                Ok(msg)
            }
        })*
    };
}

#[cfg(feature = "json")]
#[macro_export]
macro_rules! prost_to_json {

    ($($type:ty),*) => {
        $(impl ToJson for $type {
            fn to_json(&self) -> String {
                serde_json::to_string(self).unwrap()
            }
        })*
    };
}

#[cfg(test)]
mod tests {
    use prost::Message;
    use serde::{Deserialize, Serialize};
    use std::convert::TryInto;

    #[derive(Clone, PartialEq, Message, Serialize, Deserialize)]
    pub struct Hello {
        #[prost(string, tag = "1")]
        pub msg: String,
        #[prost(uint64, tag = "2")]
        pub value: u64,
    }

    #[derive(Clone, PartialEq, Message, Serialize, Deserialize)]
    struct World {
        #[prost(string, tag = "1")]
        pub msg: String,
    }

    #[test]
    fn test_prost_try_into_vec() {
        prost_into_vec!((Hello, 32), (World, 256));
        vec_try_into_prost!(Hello, World);
        let hello = Hello::default();
        let data: Vec<u8> = hello.clone().into();
        let data_ref = &data[..];

        let hello_result1: Result<Hello, prost::DecodeError> = data_ref.try_into();
        let hello_result2: Result<Hello, prost::DecodeError> = data.try_into();
        assert_eq!(hello_result1.is_ok(), true);
        assert_eq!(hello_result1.unwrap(), hello);
        assert_eq!(hello_result2.is_ok(), true);
        assert_eq!(hello_result2.unwrap(), hello);
    }

    #[cfg(feature = "json")]
    #[test]
    fn test_prost_to_json() {
        use crate::ToJson;

        prost_to_json!(Hello, World);
        let hello = Hello::default();
        let result = hello.to_json();
        assert_eq!(result, r#"{"msg":"","value":0}"#);
    }
}