use crate::FromHex;
use core::fmt;
use core::marker::PhantomData;
use serde_core::de::{Error, Visitor};
use serde_core::Deserializer;
#[inline]
pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
T: AsRef<[u8]>,
{
serialize_inner::<S, false, true>(data.as_ref(), serializer)
}
#[inline]
pub fn serialize_upper<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
T: AsRef<[u8]>,
{
serialize_inner::<S, true, true>(data.as_ref(), serializer)
}
const STACK_LEN: usize = 128;
const STREAM_LEN: usize = 4096;
fn serialize_inner<S, const UPPER: bool, const PREFIX: bool>(
data: &[u8],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
{
if data.len() <= STACK_LEN {
let mut buf = crate::impl_core::uninit_array::<u8, { STACK_LEN * 2 + 2 }>();
let prefix_len = PREFIX as usize * 2;
let len = prefix_len + data.len() * 2;
if PREFIX {
buf[0].write(b'0');
buf[1].write(b'x');
}
unsafe { crate::imp::encode::<UPPER>(data, &mut buf[prefix_len..len]) };
let s = unsafe {
core::str::from_utf8_unchecked(crate::impl_core::slice_assume_init(&buf[..len]))
};
serializer.serialize_str(s)
} else {
serializer.collect_str(&BufferedHex::<UPPER, PREFIX>(data))
}
}
struct BufferedHex<'a, const UPPER: bool, const PREFIX: bool>(&'a [u8]);
impl<const UPPER: bool, const PREFIX: bool> fmt::Display for BufferedHex<'_, UPPER, PREFIX> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use crate::output::{BufferedOutput, FormatterOutput, Output};
let mut formatter = FormatterOutput::new(f);
let mut output = BufferedOutput::<_, STREAM_LEN>::new(&mut formatter);
if PREFIX {
output.write(b"0x");
}
unsafe { crate::imp::encode::<UPPER>(self.0, &mut output) };
output.finish();
formatter.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
use core::fmt::Write;
struct Sink {
writes: usize,
bytes: usize,
fail_at: usize,
}
impl fmt::Write for Sink {
fn write_str(&mut self, s: &str) -> fmt::Result {
self.writes += 1;
if self.writes >= self.fail_at {
return Err(fmt::Error);
}
self.bytes += s.len();
Ok(())
}
}
#[test]
fn buffered_hex_batches_writes() {
let mut sink = Sink {
writes: 0,
bytes: 0,
fail_at: usize::MAX,
};
write!(sink, "{}", BufferedHex::<false, true>(&[0xab; 4097])).unwrap();
assert_eq!(sink.bytes, 8196);
assert_eq!(sink.writes, 3);
}
#[test]
fn buffered_hex_propagates_flush_errors() {
for fail_at in 1..=3 {
let mut sink = Sink {
writes: 0,
bytes: 0,
fail_at,
};
assert!(write!(sink, "{}", BufferedHex::<false, true>(&[0xab; 4097])).is_err());
assert_eq!(sink.writes, fail_at);
}
}
}
#[inline]
pub fn deserialize<'de, D, T>(deserializer: D) -> Result<T, D::Error>
where
D: Deserializer<'de>,
T: FromHex,
<T as FromHex>::Error: fmt::Display,
{
struct HexStrVisitor<T>(PhantomData<T>);
impl<T> Visitor<'_> for HexStrVisitor<T>
where
T: FromHex,
<T as FromHex>::Error: fmt::Display,
{
type Value = T;
fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str("a hex encoded string")
}
fn visit_bytes<E: Error>(self, data: &[u8]) -> Result<Self::Value, E> {
FromHex::from_hex(data).map_err(Error::custom)
}
fn visit_str<E: Error>(self, data: &str) -> Result<Self::Value, E> {
FromHex::from_hex(data.as_bytes()).map_err(Error::custom)
}
}
deserializer.deserialize_str(HexStrVisitor(PhantomData))
}
pub mod no_prefix {
#[inline]
pub fn serialize<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
T: AsRef<[u8]>,
{
super::serialize_inner::<S, false, false>(data.as_ref(), serializer)
}
#[inline]
pub fn serialize_upper<S, T>(data: T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde_core::Serializer,
T: AsRef<[u8]>,
{
super::serialize_inner::<S, true, false>(data.as_ref(), serializer)
}
pub use super::deserialize;
}