Skip to content

Commit

Permalink
Alternative to visitor and enum (#271)
Browse files Browse the repository at this point in the history
* Try if #269 (comment)
really works

* cargo fmt --

* clippy
  • Loading branch information
liamsi authored May 14, 2020
1 parent 5f47467 commit 0ff4ae3
Showing 1 changed file with 14 additions and 78 deletions.
92 changes: 14 additions & 78 deletions tendermint/src/serializers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,83 +97,20 @@ pub mod time_duration {

/// Serialize/deserialize bytes (Vec<u8>) type
pub mod bytes {
use serde::{
de::{Error, Visitor},
Deserialize, Deserializer,
};
use std::fmt;
use subtle_encoding::{base64, hex};

/// ByteStringType defines the options what an incoming string can represent.
enum ByteStringType {
Hex,
Base64,
Regular,
}

/// The Visitor struct to decode the incoming string.
struct BytesVisitor {
string_type: ByteStringType,
}

/// The Visitor implementation
impl<'de> Visitor<'de> for BytesVisitor {
type Value = Vec<u8>;

/// Description of expected input
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
match self.string_type {
ByteStringType::Hex => {
formatter.write_str("Hex-encoded byte-array in a String or null")
}
ByteStringType::Base64 => {
formatter.write_str("Base64-encoded byte-array in a String or null")
}
ByteStringType::Regular => formatter.write_str("Byte-array in a String or null"),
}
}

/// If incoming is 'null', return an empty array.
fn visit_none<E>(self) -> Result<Self::Value, E>
where
E: Error,
{
Ok(vec![])
}

/// Decode the incoming string based on what string type it is.
fn visit_some<D>(
self,
deserializer: D,
) -> Result<Self::Value, <D as Deserializer<'de>>::Error>
where
D: Deserializer<'de>,
{
let string = String::deserialize(deserializer)?;

match self.string_type {
ByteStringType::Hex => hex::decode_upper(&string)
.or_else(|_| hex::decode(&string))
.map_err(Error::custom),
ByteStringType::Base64 => base64::decode(&string).map_err(Error::custom),
ByteStringType::Regular => Ok(string.as_bytes().to_vec()),
}
}
}

/// Serialize into hexstring, deserialize from hexstring
pub mod hexstring {
use serde::{ser::Error, Deserializer, Serializer};
use serde::{Deserialize, Deserializer, Serializer};
use subtle_encoding::hex;

/// Deserialize hexstring into Vec<u8>
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(super::BytesVisitor {
string_type: super::ByteStringType::Hex,
})
let string = Option::<String>::deserialize(deserializer)?.unwrap_or_default();
hex::decode_upper(&string)
.or_else(|_| hex::decode(&string))
.map_err(serde::de::Error::custom)
}

/// Serialize from T into hexstring
Expand All @@ -183,24 +120,23 @@ pub mod bytes {
T: AsRef<[u8]>,
{
let hex_bytes = hex::encode(value.as_ref());
let hex_string = String::from_utf8(hex_bytes).map_err(Error::custom)?;
let hex_string = String::from_utf8(hex_bytes).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&hex_string)
}
}

/// Serialize into base64string, deserialize from base64string
pub mod base64string {
use serde::{ser::Error, Deserializer, Serializer};
use serde::{Deserialize, Deserializer, Serializer};
use subtle_encoding::base64;

/// Deserialize base64string into Vec<u8>
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(super::BytesVisitor {
string_type: super::ByteStringType::Base64,
})
let string = Option::<String>::deserialize(deserializer)?.unwrap_or_default();
base64::decode(&string).map_err(serde::de::Error::custom)
}

/// Serialize from T into base64string
Expand All @@ -210,23 +146,23 @@ pub mod bytes {
T: AsRef<[u8]>,
{
let base64_bytes = base64::encode(value.as_ref());
let base64_string = String::from_utf8(base64_bytes).map_err(Error::custom)?;
let base64_string =
String::from_utf8(base64_bytes).map_err(serde::ser::Error::custom)?;
serializer.serialize_str(&base64_string)
}
}

/// Serialize into string, deserialize from string
pub mod string {
use serde::{ser::Error, Deserializer, Serializer};
use serde::{ser::Error, Deserialize, Deserializer, Serializer};

/// Deserialize string into Vec<u8>
pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_option(super::BytesVisitor {
string_type: super::ByteStringType::Regular,
})
let string = Option::<String>::deserialize(deserializer)?.unwrap_or_default();
Ok(string.as_bytes().to_vec())
}

/// Serialize from T into string
Expand Down

0 comments on commit 0ff4ae3

Please sign in to comment.