-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
229 additions
and
202 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,211 @@ | ||
use core::fmt; | ||
use core::marker::PhantomData; | ||
|
||
use serde::{ | ||
de::{Error, Visitor}, | ||
Serialize, Serializer, | ||
}; | ||
|
||
#[cfg(feature = "alloc")] | ||
use ::alloc::vec::Vec; | ||
|
||
pub(crate) fn serialize_hex<S, T, const UPPERCASE: bool>( | ||
value: &T, | ||
serializer: S, | ||
) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
T: AsRef<[u8]>, | ||
{ | ||
#[cfg(feature = "alloc")] | ||
if UPPERCASE { | ||
return base16ct::upper::encode_string(value.as_ref()).serialize(serializer); | ||
} else { | ||
return base16ct::lower::encode_string(value.as_ref()).serialize(serializer); | ||
} | ||
#[cfg(not(feature = "alloc"))] | ||
{ | ||
let _ = value; | ||
let _ = serializer; | ||
return Err(S::Error::custom( | ||
"serializer is human readable, which requires the `alloc` crate feature", | ||
)); | ||
} | ||
} | ||
|
||
pub(crate) fn serialize_hex_lower_or_bin<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
T: AsRef<[u8]>, | ||
{ | ||
if serializer.is_human_readable() { | ||
serialize_hex::<_, _, false>(value, serializer) | ||
} else { | ||
serializer.serialize_bytes(value.as_ref()) | ||
} | ||
} | ||
|
||
/// Serialize the given type as upper case hex when using human-readable | ||
/// formats or binary if the format is binary. | ||
pub(crate) fn serialize_hex_upper_or_bin<S, T>(value: &T, serializer: S) -> Result<S::Ok, S::Error> | ||
where | ||
S: Serializer, | ||
T: AsRef<[u8]>, | ||
{ | ||
if serializer.is_human_readable() { | ||
serialize_hex::<_, _, true>(value, serializer) | ||
} else { | ||
serializer.serialize_bytes(value.as_ref()) | ||
} | ||
} | ||
|
||
pub(crate) trait LengthCheck { | ||
fn length_check(buffer_length: usize, data_length: usize) -> bool; | ||
fn expecting( | ||
formatter: &mut fmt::Formatter<'_>, | ||
data_type: &str, | ||
data_length: usize, | ||
) -> fmt::Result; | ||
} | ||
|
||
pub(crate) struct ExactLength; | ||
|
||
impl LengthCheck for ExactLength { | ||
fn length_check(buffer_length: usize, data_length: usize) -> bool { | ||
buffer_length == data_length | ||
} | ||
fn expecting( | ||
formatter: &mut fmt::Formatter<'_>, | ||
data_type: &str, | ||
data_length: usize, | ||
) -> fmt::Result { | ||
write!(formatter, "{} of length {}", data_type, data_length) | ||
} | ||
} | ||
|
||
pub(crate) struct UpperBound; | ||
|
||
impl LengthCheck for UpperBound { | ||
fn length_check(buffer_length: usize, data_length: usize) -> bool { | ||
buffer_length >= data_length | ||
} | ||
fn expecting( | ||
formatter: &mut fmt::Formatter<'_>, | ||
data_type: &str, | ||
data_length: usize, | ||
) -> fmt::Result { | ||
write!( | ||
formatter, | ||
"{} with a maximum length of {}", | ||
data_type, data_length | ||
) | ||
} | ||
} | ||
|
||
pub(crate) struct StrIntoBufVisitor<'b, T: LengthCheck>(pub &'b mut [u8], pub PhantomData<T>); | ||
|
||
impl<'de, 'b, T: LengthCheck> Visitor<'de> for StrIntoBufVisitor<'b, T> { | ||
type Value = (); | ||
|
||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
T::expecting(formatter, "a string", self.0.len() * 2) | ||
} | ||
|
||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> | ||
where | ||
E: Error, | ||
{ | ||
if !T::length_check(self.0.len() * 2, v.len()) { | ||
return Err(Error::invalid_length(v.len(), &self)); | ||
} | ||
// TODO: Map `base16ct::Error::InvalidLength` to `Error::invalid_length`. | ||
base16ct::mixed::decode(v, self.0) | ||
.map(|_| ()) | ||
.map_err(E::custom) | ||
} | ||
} | ||
|
||
#[cfg(feature = "alloc")] | ||
pub(crate) struct StrIntoVecVisitor; | ||
|
||
impl<'de> Visitor<'de> for StrIntoVecVisitor { | ||
type Value = Vec<u8>; | ||
|
||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(formatter, "a string") | ||
} | ||
|
||
fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> | ||
where | ||
E: Error, | ||
{ | ||
base16ct::mixed::decode_vec(v).map_err(E::custom) | ||
} | ||
} | ||
|
||
pub(crate) struct SliceVisitor<'b, T: LengthCheck>(pub &'b mut [u8], pub PhantomData<T>); | ||
|
||
impl<'de, 'b, T: LengthCheck> Visitor<'de> for SliceVisitor<'b, T> { | ||
type Value = (); | ||
|
||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
T::expecting(formatter, "an array", self.0.len()) | ||
} | ||
|
||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> | ||
where | ||
E: Error, | ||
{ | ||
// Workaround for | ||
// https://github.com/rust-lang/rfcs/blob/b1de05846d9bc5591d753f611ab8ee84a01fa500/text/2094-nll.md#problem-case-3-conditional-control-flow-across-functions | ||
if T::length_check(self.0.len(), v.len()) { | ||
let buffer = &mut self.0[..v.len()]; | ||
buffer.copy_from_slice(v); | ||
return Ok(()); | ||
} | ||
|
||
Err(E::invalid_length(v.len(), &self)) | ||
} | ||
|
||
#[cfg(feature = "alloc")] | ||
fn visit_byte_buf<E>(self, mut v: Vec<u8>) -> Result<Self::Value, E> | ||
where | ||
E: Error, | ||
{ | ||
// Workaround for | ||
// https://github.com/rust-lang/rfcs/blob/b1de05846d9bc5591d753f611ab8ee84a01fa500/text/2094-nll.md#problem-case-3-conditional-control-flow-across-functions | ||
if T::length_check(self.0.len(), v.len()) { | ||
let buffer = &mut self.0[..v.len()]; | ||
buffer.swap_with_slice(&mut v); | ||
return Ok(()); | ||
} | ||
|
||
Err(E::invalid_length(v.len(), &self)) | ||
} | ||
} | ||
|
||
#[cfg(feature = "alloc")] | ||
pub(crate) struct VecVisitor; | ||
|
||
#[cfg(feature = "alloc")] | ||
impl<'de> Visitor<'de> for VecVisitor { | ||
type Value = Vec<u8>; | ||
|
||
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
write!(formatter, "a bytestring") | ||
} | ||
|
||
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> | ||
where | ||
E: Error, | ||
{ | ||
Ok(v.into()) | ||
} | ||
|
||
fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> | ||
where | ||
E: Error, | ||
{ | ||
Ok(v) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.