pub extern crate serde;
extern crate serde_json;
extern crate rmp_serde;
use serde::{Deserialize, Serialize};
use std::convert::TryFrom;
pub mod prelude;
pub fn encode<T: serde::Serialize>(val: &T) -> Result<Vec<u8>, rmp_serde::encode::Error> {
let buf = Vec::with_capacity(128);
let mut se = rmp_serde::encode::Serializer::new(buf)
.with_struct_map()
.with_string_variants();
val.serialize(&mut se)?;
Ok(se.into_inner())
}
pub fn decode<'a, R, T>(rd: &'a R) -> Result<T, rmp_serde::decode::Error>
where
R: AsRef<[u8]> + ?Sized,
T: Deserialize<'a>,
{
rmp_serde::from_read_ref(rd)
}
#[derive(
Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord, Serialize, Deserialize, thiserror::Error,
)]
pub enum SerializedBytesError {
ToBytes(String),
FromBytes(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 {
format!("{:?}", sb)
}
}
#[derive(Clone)]
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)]
#[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);
serde_transcode::transcode(&mut deserializer, &mut serializer).unwrap();
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> {
match $crate::encode(t) {
Ok(v) => Ok($crate::SerializedBytes::from($crate::UnsafeBytes::from(v))),
Err(e) => Err($crate::SerializedBytesError::ToBytes(e.to_string())),
}
}
}
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> {
match $crate::decode(sb.bytes()) {
Ok(v) => Ok(v),
Err(e) => Err($crate::SerializedBytesError::FromBytes(e.to_string())),
}
}
}
)*
};
}
holochain_serial!(());
impl Default for SerializedBytes {
fn default() -> Self {
SerializedBytes::try_from(()).unwrap()
}
}
#[cfg(test)]
pub mod tests {
use super::prelude::*;
use std::convert::TryInto;
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
struct Foo {
inner: String,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
struct Bar {
whatever: Vec<u8>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
enum BazResult {
Ok(Vec<u8>),
Err(String),
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
struct Baz {
wow: Option<BazResult>,
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
struct Tiny(u8);
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
struct SomeBytes(Vec<u8>);
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone, SerializedBytes)]
struct IncludesSerializedBytes {
inner: SerializedBytes,
}
fn fixture_foo() -> Foo {
Foo {
inner: "foo".into(),
}
}
fn fixture_bar() -> Bar {
Bar {
whatever: vec![1_u8, 2_u8, 3_u8],
}
}
#[test]
fn round_trip() {
macro_rules! do_test {
( $t:ty, $i:expr, $o:expr ) => {{
let i = $i;
let sb: SerializedBytes = i.clone().try_into().unwrap();
println!("{:?}", &sb);
assert_eq!(&$o, sb.bytes(),);
let returned: $t = sb.try_into().unwrap();
assert_eq!(returned, i);
let sb2 = SerializedBytes::try_from(&i).unwrap();
assert_eq!(&$o, sb2.bytes());
}};
}
do_test!(
Foo,
fixture_foo(),
vec![
129_u8, 165_u8, 105_u8, 110_u8, 110_u8, 101_u8, 114_u8, 163_u8, 102_u8, 111_u8,
111_u8,
]
);
do_test!(
Bar,
fixture_bar(),
vec![
129_u8, 168_u8, 119_u8, 104_u8, 97_u8, 116_u8, 101_u8, 118_u8, 101_u8, 114_u8,
147_u8, 1_u8, 2_u8, 3_u8,
]
);
do_test!(
Baz,
Baz {
wow: Some(BazResult::Ok(vec![2, 5, 6]))
},
vec![129, 163, 119, 111, 119, 129, 162, 79, 107, 147, 2, 5, 6]
);
do_test!(Tiny, Tiny(5), vec![5]);
do_test!(
SomeBytes,
SomeBytes(vec![1_u8, 90_u8, 155_u8]),
vec![147, 1, 90, 204, 155]
);
do_test!((), (), vec![192]);
do_test!(
IncludesSerializedBytes,
IncludesSerializedBytes {
inner: fixture_foo().try_into().unwrap()
},
vec![
129, 165, 105, 110, 110, 101, 114, 196, 11, 129, 165, 105, 110, 110, 101, 114, 163,
102, 111, 111
]
);
}
#[test]
fn self_noop() {
let sb: SerializedBytes = fixture_foo().try_into().unwrap();
let sb_2: SerializedBytes = sb.clone().try_into().unwrap();
assert_eq!(sb, sb_2,);
}
#[test]
fn provide_own_bytes() {
let bytes = vec![1_u8, 90_u8, 155_u8];
let own_bytes = UnsafeBytes::from(bytes.clone());
let sb: SerializedBytes = own_bytes.clone().into();
assert_eq!(sb.bytes(), &bytes,);
let own_bytes_restored: UnsafeBytes = sb.into();
assert_eq!(&own_bytes.0, &own_bytes_restored.0,);
}
#[test]
fn default_test() {
assert_eq!(&vec![192_u8], SerializedBytes::default().bytes());
}
}