feat(primitives): Enable serde of ledger structs (#169)

This commit is contained in:
Santiago Carmuega 2022-08-12 19:43:56 -03:00 committed by GitHub
parent 1f0eb3bfc0
commit 9845fc4040
22 changed files with 584 additions and 270 deletions

View file

@ -2,10 +2,9 @@
//!
//! we expose two helper objects:
//!
//! * [`Hasher`] to help streaming objects or bytes into a hasher
//! and computing a hash without allocating extra memory due to
//! the required **CBOR** encoding for everything by the cardano
//! protocol
//! * [`Hasher`] to help streaming objects or bytes into a hasher and computing
//! a hash without allocating extra memory due to the required **CBOR**
//! encoding for everything by the cardano protocol
//! * [`struct@Hash`] a conveniently strongly typed byte array
//!
//! The algorithm exposed here is `Blake2b`. We currently support two
@ -30,5 +29,6 @@
#[allow(clippy::module_inception)]
mod hash;
mod hasher;
mod serde;
pub use self::{hash::Hash, hasher::Hasher};

View file

@ -0,0 +1,97 @@
use std::fmt;
use std::str::FromStr;
use serde::de::{Error, Unexpected, Visitor};
use serde::{Deserialize, Deserializer, Serialize};
use super::Hash;
impl<const BYTES: usize> Serialize for Hash<BYTES> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
struct HashVisitor<const BYTES: usize> {}
impl<'de, const BYTES: usize> Visitor<'de> for HashVisitor<BYTES> {
type Value = Hash<BYTES>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
write!(formatter, "a hex string representing {} bytes", BYTES)
}
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: Error,
{
match Hash::<BYTES>::from_str(s) {
Ok(x) => Ok(x),
Err(_) => Err(Error::invalid_value(Unexpected::Str(s), &self)),
}
}
}
impl<'de, const BYTES: usize> Deserialize<'de> for Hash<BYTES> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_str(HashVisitor::<BYTES> {})
}
}
#[cfg(test)]
mod tests {
use serde_test::{assert_de_tokens_error, assert_tokens, Token};
use super::*;
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
struct Dummy {
hash1: Hash<28>,
hash2: Hash<32>,
}
#[test]
fn output_tokens() {
let dummy = Dummy {
hash1: "276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3"
.parse()
.unwrap(),
hash2: "0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21"
.parse()
.unwrap(),
};
assert_tokens(
&dummy,
&[
Token::Struct {
name: "Dummy",
len: 2,
},
Token::Str("hash1"),
Token::Str("276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3"),
Token::Str("hash2"),
Token::Str("0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21"),
Token::StructEnd,
],
);
}
#[test]
fn invalid_str() {
assert_de_tokens_error::<Dummy>(
&[
Token::Map { len: Some(2) },
Token::Str("hash1"),
Token::Str("27"),
],
"invalid value: string \"27\", expected a hex string representing 28 bytes",
);
}
}