extern crate rmp_serde;
extern crate serde;
extern crate serde_json;
use serde::{Deserialize, Serialize};
use std::convert::Infallible;
use std::convert::TryFrom;
pub mod prelude;
#[cfg_attr(feature = "trace", tracing::instrument)]
pub fn encode<T: serde::Serialize + std::fmt::Debug>(
val: &T,
) -> Result<Vec<u8>, SerializedBytesError> {
let buf = Vec::with_capacity(128);
let mut se = rmp_serde::encode::Serializer::new(buf).with_struct_map();
val.serialize(&mut se).map_err(|err| {
#[cfg(feature = "trace")]
tracing::warn!("Failed to serialize input");
SerializedBytesError::Serialize(err.to_string())
})?;
let ret = se.into_inner();
#[cfg(feature = "trace")]
tracing::trace!(
"Serialized {} input into {:?}",
std::any::type_name::<T>(),
ret
);
Ok(ret)
}
#[cfg_attr(feature = "trace", tracing::instrument)]
pub fn decode<'a, R, T>(input: &'a R) -> Result<T, SerializedBytesError>
where
R: AsRef<[u8]> + ?Sized + std::fmt::Debug,
T: Deserialize<'a> + std::fmt::Debug,
{
let ret = rmp_serde::from_slice(input.as_ref()).map_err(|err| {
#[cfg(feature = "trace")]
tracing::warn!(
"Failed to deserialize input into: {}",
std::any::type_name::<T>()
);
SerializedBytesError::Deserialize(err.to_string())
})?;
#[cfg(feature = "trace")]
tracing::trace!("Deserialized input into: {:?}", ret);
Ok(ret)
}
#[derive(
Clone,
Debug,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
serde::Serialize,
serde::Deserialize,
thiserror::Error,
)]
pub enum SerializedBytesError {
Serialize(String),
Deserialize(String),
}
impl std::fmt::Display for SerializedBytesError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}
impl From<SerializedBytesError> for String {
fn from(sb: SerializedBytesError) -> Self {
match sb {
SerializedBytesError::Serialize(s) => s,
SerializedBytesError::Deserialize(s) => s,
}
}
}
impl From<Infallible> for SerializedBytesError {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
#[derive(Clone, Debug)]
#[cfg_attr(
feature = "fuzzing",
derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
)]
pub struct UnsafeBytes(Vec<u8>);
impl From<Vec<u8>> for UnsafeBytes {
fn from(v: Vec<u8>) -> Self {
Self(v)
}
}
impl From<UnsafeBytes> for Vec<u8> {
fn from(unsafe_bytes: UnsafeBytes) -> Vec<u8> {
unsafe_bytes.0
}
}
impl From<UnsafeBytes> for SerializedBytes {
fn from(b: UnsafeBytes) -> Self {
SerializedBytes(b.0)
}
}
impl From<SerializedBytes> for UnsafeBytes {
fn from(sb: SerializedBytes) -> Self {
UnsafeBytes(sb.0)
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Hash)]
#[cfg_attr(
feature = "fuzzing",
derive(arbitrary::Arbitrary, proptest_derive::Arbitrary)
)]
#[repr(transparent)]
pub struct SerializedBytes(#[serde(with = "serde_bytes")] Vec<u8>);
impl SerializedBytes {
pub fn bytes(&self) -> &Vec<u8> {
&self.0
}
}
impl std::fmt::Debug for SerializedBytes {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut deserializer = rmp_serde::Deserializer::from_read_ref(&self.0);
let writer = Vec::new();
let mut serializer = serde_json::ser::Serializer::new(writer);
if serde_transcode::transcode(&mut deserializer, &mut serializer).is_err() {
write!(f, "<invalid msgpack>")
} else {
let s = unsafe { String::from_utf8_unchecked(serializer.into_inner()) };
write!(f, "{}", s)
}
}
}
#[macro_export]
macro_rules! holochain_serial {
( $( $t:ty ),* ) => {
$(
impl std::convert::TryFrom<&$t> for $crate::SerializedBytes {
type Error = $crate::SerializedBytesError;
fn try_from(t: &$t) -> std::result::Result<$crate::SerializedBytes, $crate::SerializedBytesError> {
$crate::encode(t).map(|v|
$crate::SerializedBytes::from($crate::UnsafeBytes::from(v))
)
}
}
impl std::convert::TryFrom<$t> for $crate::SerializedBytes {
type Error = $crate::SerializedBytesError;
fn try_from(t: $t) -> std::result::Result<$crate::SerializedBytes, $crate::SerializedBytesError> {
$crate::SerializedBytes::try_from(&t)
}
}
impl std::convert::TryFrom<$crate::SerializedBytes> for $t {
type Error = $crate::SerializedBytesError;
fn try_from(sb: $crate::SerializedBytes) -> std::result::Result<$t, $crate::SerializedBytesError> {
$crate::decode(sb.bytes())
}
}
)*
};
}
holochain_serial!(());
impl Default for SerializedBytes {
fn default() -> Self {
SerializedBytes::try_from(()).unwrap()
}
}
impl<'a> TryFrom<&'a SerializedBytes> for SerializedBytes {
type Error = SerializedBytesError;
fn try_from(s: &'a SerializedBytes) -> Result<Self, Self::Error> {
Ok(s.clone())
}
}