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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#[cfg(all(feature = "deser_borsh", feature = "deser_json"))]
pub trait Serialize: borsh::BorshSerialize + serde::Serialize {}
#[cfg(all(feature = "deser_borsh", feature = "deser_json"))]
impl<T> Serialize for T where T: borsh::BorshSerialize + serde::Serialize {}
#[cfg(all(feature = "deser_borsh", feature = "deser_json"))]
pub trait Deserialize: borsh::BorshDeserialize + serde::de::DeserializeOwned {}
#[cfg(all(feature = "deser_borsh", feature = "deser_json"))]
impl<T> Deserialize for T where T: borsh::BorshDeserialize + serde::de::DeserializeOwned {}

#[cfg(all(feature = "deser_borsh", not(feature = "deser_json")))]
pub trait Serialize: borsh::BorshSerialize {}
#[cfg(all(feature = "deser_borsh", not(feature = "deser_json")))]
impl<T> Serialize for T where T: borsh::BorshSerialize {}
#[cfg(all(feature = "deser_borsh", not(feature = "deser_json")))]
pub trait Deserialize: borsh::BorshDeserialize {}
#[cfg(all(feature = "deser_borsh", not(feature = "deser_json")))]
impl<T> Deserialize for T where T: borsh::BorshDeserialize {}

#[derive(Debug, Copy, Clone)]
pub enum Deser {
    #[cfg(feature = "deser_borsh")]
    Borsh,
    #[cfg(feature = "deser_json")]
    Json,
}
impl Deser {
    pub fn from_slice<T>(&self, bytes: &[u8]) -> Result<T, Error>
    where
        T: Deserialize,
    {
        match self {
            #[cfg(feature = "deser_borsh")]
            Self::Borsh => {
                Ok(<T as borsh::BorshDeserialize>::try_from_slice(bytes)
                    // mapping because it's actually a `std::io::Error`, so ?
                    // would convert the wrong type.
                    .map_err(Error::Borsh)?)
            }
            #[cfg(feature = "deser_json")]
            Self::Json => Ok(serde_json::from_slice(bytes)?),
        }
    }
    pub fn to_vec<T>(&self, t: &T) -> Result<Vec<u8>, Error>
    where
        T: Serialize,
    {
        match self {
            #[cfg(feature = "deser_borsh")]
            Self::Borsh => {
                Ok(<T as borsh::BorshSerialize>::try_to_vec(t)
                    // mapping because it's actually a `std::io::Error`, so ?
                    // would convert the wrong type.
                    .map_err(Error::Borsh)?)
            }
            #[cfg(feature = "deser_json")]
            Self::Json => Ok(cjson::to_vec(t)?),
        }
    }
}
#[cfg(all(feature = "deser_borsh"))]
impl Default for Deser {
    fn default() -> Self {
        Self::Borsh
    }
}
#[cfg(all(feature = "deser_json", not(feature = "deser_borsh")))]
impl Default for Deser {
    fn default() -> Self {
        Self::Json
    }
}
#[derive(Debug, thiserror::Error)]
pub enum Error {
    /// A [`borsh`] crate error.
    ///
    /// They return an io::Error, the std::io type is not a bug.
    #[cfg(feature = "deser_borsh")]
    #[error("borsh error: `{0:?}`")]
    Borsh(std::io::Error),
    /// A [`serde_json`] crate error.
    #[cfg(feature = "deser_json")]
    #[error("serde_json error: `{0:?}`")]
    SerdeJson(#[from] serde_json::Error),
    /// A [`cjson`] crate error.
    #[cfg(feature = "deser_json")]
    #[error("cjson error: `{0:?}`")]
    Cjson(cjson::Error),
}
#[cfg(feature = "deser_json")]
impl From<cjson::Error> for Error {
    fn from(err: cjson::Error) -> Self {
        Self::Cjson(err)
    }
}
#[cfg(test)]
pub mod test {
    use {super::*, crate::value::Value};
    #[cfg(feature = "deser_borsh")]
    #[tokio::test]
    async fn borsh() {
        let mut env_builder = env_logger::builder();
        env_builder.is_test(true);
        if std::env::var("RUST_LOG").is_err() {
            env_builder.filter(Some("fixity"), log::LevelFilter::Debug);
        }
        let expected = Value::from(1);
        let bytes = Deser::to_vec(&Deser::Borsh, &expected).unwrap();
        let got = Deser::from_slice::<Value>(&Deser::Borsh, &bytes).unwrap();
        assert_eq!(expected, got);
    }
    #[cfg(feature = "deser_json")]
    #[tokio::test]
    async fn json() {
        let mut env_builder = env_logger::builder();
        env_builder.is_test(true);
        if std::env::var("RUST_LOG").is_err() {
            env_builder.filter(Some("fixity"), log::LevelFilter::Debug);
        }
        let expected = Value::from(1);
        let bytes = Deser::to_vec(&Deser::Json, &expected).unwrap();
        let got = Deser::from_slice::<Value>(&Deser::Json, &bytes).unwrap();
        assert_eq!(expected, got);
    }
}