use std::collections::HashMap;
use std::fmt::{self, Debug};
use std::hash::Hash;
use std::marker::Sized;
use byteorder::{self, ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};
use rmp::decode::{DecodeStringError, MarkerReadError, NumValueReadError, ValueReadError};
use rmp::encode::ValueWriteError;
use rmp::Marker;
use num_traits::cast::FromPrimitive;
#[derive(Debug)]
pub enum Error {
IO(std::io::Error),
InvalidStructLength {
expected: usize,
actual: usize,
},
IncompatibleSchema(String),
DecodeStringError(),
ValueWriteError(ValueWriteError),
ValueReadError(ValueReadError),
NumValueReadError(NumValueReadError),
MarkerReadError(MarkerReadError),
WrongExtForTimestamp(i8),
WrongLenForTimestamp(u8),
UnwrittableUnionVariant {
union: &'static str,
variant: &'static str,
},
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Error::IO(err)
}
}
impl From<std::string::FromUtf8Error> for Error {
fn from(_err: std::string::FromUtf8Error) -> Self {
Error::DecodeStringError()
}
}
impl From<std::str::Utf8Error> for Error {
fn from(_err: std::str::Utf8Error) -> Self {
Error::DecodeStringError()
}
}
impl From<MarkerReadError> for Error {
fn from(err: MarkerReadError) -> Self {
Error::MarkerReadError(err)
}
}
impl From<ValueWriteError> for Error {
fn from(err: ValueWriteError) -> Self {
Error::ValueWriteError(err)
}
}
impl From<ValueReadError> for Error {
fn from(err: ValueReadError) -> Self {
Error::ValueReadError(err)
}
}
impl From<NumValueReadError> for Error {
fn from(err: NumValueReadError) -> Self {
Error::NumValueReadError(err)
}
}
impl<'a> From<DecodeStringError<'a>> for Error {
fn from(_err: DecodeStringError<'a>) -> Self {
Error::DecodeStringError()
}
}
impl std::error::Error for Error {}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}", self)
}
}
pub trait Mapping: Default + Debug + Send + Sync + 'static {}
pub trait Factual<M>
where
M: Mapping,
{
fn write<W: Write>(&self, mapping: &M, wr: &mut W) -> Result<(), Error>;
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error>
where
Self: Sized;
#[inline]
fn subread<R: Read, T>(rd: &mut Reader<R>) -> Result<T, Error>
where
Self: Sized,
T: Factual<M>,
{
T::read(rd)
}
}
pub struct Reader<R>
where
R: Read,
{
rd: R,
buf: Vec<u8>,
marker: Option<Marker>,
}
impl<R> Reader<R>
where
R: Read,
{
pub fn new(rd: R) -> Self {
Self {
rd,
buf: Vec::with_capacity(128),
marker: None,
}
}
#[inline]
fn fetch_marker(&mut self) -> Result<Marker, Error> {
match self.marker.take() {
Some(marker) => Ok(marker),
None => Ok(rmp::decode::read_marker(&mut self.rd)?),
}
}
#[inline]
fn read_slice(&mut self, len: usize) -> Result<&[u8], Error> {
self.buf.resize(len, 0u8);
self.rd.read_exact(&mut self.buf[..])?;
Ok(&self.buf[..])
}
#[inline]
pub fn read_array_len(&mut self) -> Result<usize, Error> {
let marker = self.fetch_marker()?;
Ok(match marker {
Marker::FixArray(len) => len as usize,
Marker::Array16 => rmp::decode::read_data_u16(self)? as usize,
Marker::Array32 => rmp::decode::read_data_u32(self)? as usize,
_ => return Err(ValueReadError::TypeMismatch(marker).into()),
})
}
#[inline]
pub fn read_bin_len(&mut self) -> Result<usize, Error> {
let marker = self.fetch_marker()?;
Ok(match marker {
Marker::Bin8 => rmp::decode::read_data_u8(self)? as usize,
Marker::Bin16 => rmp::decode::read_data_u16(self)? as usize,
Marker::Bin32 => rmp::decode::read_data_u32(self)? as usize,
_ => return Err(ValueReadError::TypeMismatch(marker).into()),
})
}
#[inline]
pub fn read_bin(&mut self) -> Result<Vec<u8>, Error> {
let len = self.read_bin_len()?;
let mut res = vec![0u8; len];
self.read_exact(&mut res)?;
Ok(res)
}
#[inline]
pub fn read_map_len(&mut self) -> Result<usize, Error> {
let marker = self.fetch_marker()?;
Ok(match marker {
Marker::FixMap(len) => len as usize,
Marker::Map16 => rmp::decode::read_data_u16(self)? as usize,
Marker::Map32 => rmp::decode::read_data_u32(self)? as usize,
_ => return Err(ValueReadError::TypeMismatch(marker).into()),
})
}
#[inline]
pub fn read_int<T>(&mut self) -> Result<T, Error>
where
T: FromPrimitive,
{
let marker = self.fetch_marker()?;
match marker {
Marker::FixPos(val) => T::from_u8(val),
Marker::FixNeg(val) => T::from_i8(val),
Marker::U8 => T::from_u8(rmp::decode::read_data_u8(self)?),
Marker::U16 => T::from_u16(rmp::decode::read_data_u16(self)?),
Marker::U32 => T::from_u32(rmp::decode::read_data_u32(self)?),
Marker::U64 => T::from_u64(rmp::decode::read_data_u64(self)?),
Marker::I8 => T::from_i8(rmp::decode::read_data_i8(self)?),
Marker::I16 => T::from_i16(rmp::decode::read_data_i16(self)?),
Marker::I32 => T::from_i32(rmp::decode::read_data_i32(self)?),
Marker::I64 => T::from_i64(rmp::decode::read_data_i64(self)?),
marker => return Err(NumValueReadError::TypeMismatch(marker).into()),
}
.ok_or_else(|| NumValueReadError::OutOfRange.into())
}
#[inline]
pub fn read_bool(&mut self) -> Result<bool, Error> {
let marker = self.fetch_marker()?;
match marker {
Marker::True => Ok(true),
Marker::False => Ok(false),
marker => Err(ValueReadError::TypeMismatch(marker).into()),
}
}
#[inline]
pub fn expect_marker(&mut self, expected: Marker) -> Result<(), Error> {
let marker = self.fetch_marker()?;
if marker == expected {
return Ok(());
}
Err(ValueReadError::TypeMismatch(marker).into())
}
#[inline]
pub fn expect_array_len(&mut self, expected: usize) -> Result<(), Error> {
let actual = self.read_array_len()?;
if expected != actual {
return Err(Error::InvalidStructLength { expected, actual });
}
Ok(())
}
#[inline]
pub fn read_str_len(&mut self) -> Result<usize, Error> {
let marker = self.fetch_marker()?;
Ok(match marker {
Marker::FixStr(len) => len as usize,
Marker::Str8 => rmp::decode::read_data_u8(self)? as usize,
Marker::Str16 => rmp::decode::read_data_u16(self)? as usize,
Marker::Str32 => rmp::decode::read_data_u32(self)? as usize,
_ => return Err(ValueReadError::TypeMismatch(marker).into()),
})
}
}
impl<R> Read for Reader<R>
where
R: Read,
{
#[inline]
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
self.rd.read(buf)
}
#[inline]
fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> {
self.rd.read_exact(buf)
}
}
impl<T, M> Factual<M> for Option<T>
where
T: Factual<M>,
M: Mapping,
{
fn write<W: Write>(&self, mapping: &M, wr: &mut W) -> Result<(), Error> {
match self {
Some(v) => v.write(mapping, wr)?,
None => rmp::encode::write_nil(wr)?,
};
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
match rmp::decode::read_marker(rd)? {
Marker::Null => Ok(None),
marker => {
rd.marker = Some(marker);
Ok(Some(T::read(rd)?))
}
}
}
}
impl<'a, M> Factual<M> for &'a str
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_str(wr, self)?;
Ok(())
}
fn read<R: Read>(_rd: &mut Reader<R>) -> Result<Self, Error> {
unimplemented!()
}
}
impl<M> Factual<M> for String
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_str(wr, self)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
let len = rd.read_str_len()?;
let bytes = rd.read_slice(len)?;
let res = std::str::from_utf8(bytes)?.to_string();
Ok(res)
}
}
impl<M> Factual<M> for chrono::DateTime<chrono::offset::Utc>
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
let tv_sec: i64 = self.timestamp();
let tv_nsec: u32 = self.timestamp_subsec_nanos();
if tv_sec >> 34 == 0 {
#[allow(clippy::cast_lossless)]
let data64: u64 = ((tv_nsec as u64) << 34) | tv_sec as u64;
if data64 & 0xFFFF_FFFF_0000_0000 == 0 {
let data32 = data64 as u32;
wr.write_u8(Marker::FixExt4.to_u8())?;
wr.write_i8(-1)?;
wr.write_u32::<byteorder::BigEndian>(data32)?;
} else {
wr.write_u8(Marker::FixExt8.to_u8())?;
wr.write_i8(-1)?;
wr.write_u64::<byteorder::BigEndian>(data64)?;
}
} else {
wr.write_u8(Marker::Ext8.to_u8())?;
wr.write_u8(12)?;
wr.write_i8(-1)?;
wr.write_u32::<byteorder::BigEndian>(tv_nsec)?;
wr.write_i64::<byteorder::BigEndian>(tv_sec)?;
}
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
let marker = rd.fetch_marker()?;
match marker {
Marker::FixExt4 => {
let typ = rd.read_i8()?;
if typ != -1 {
return Err(Error::WrongExtForTimestamp(typ));
}
let data32 = rd.read_u32::<byteorder::BigEndian>()?;
#[allow(clippy::cast_lossless)]
let naive = chrono::NaiveDateTime::from_timestamp(data32 as i64, 0);
Ok(chrono::DateTime::<chrono::offset::Utc>::from_utc(
naive,
chrono::offset::Utc,
))
}
Marker::FixExt8 => {
let typ = rd.read_i8()?;
if typ != -1 {
return Err(Error::WrongExtForTimestamp(typ));
}
let data64 = rd.read_u64::<byteorder::BigEndian>()?;
let tv_nsec = data64 >> 34;
let tv_sec = data64 & 0x0000_0003_FFFF_FFFF;
#[allow(clippy::cast_lossless)]
let naive = chrono::NaiveDateTime::from_timestamp(tv_sec as i64, tv_nsec as u32);
Ok(chrono::DateTime::<chrono::offset::Utc>::from_utc(
naive,
chrono::offset::Utc,
))
}
Marker::Ext8 => {
let len = rd.read_u8()?;
if len != 12 {
return Err(Error::WrongLenForTimestamp(len));
}
let typ = rd.read_i8()?;
if typ != -1 {
return Err(Error::WrongExtForTimestamp(typ));
}
let tv_nsec = rd.read_u32::<byteorder::BigEndian>()?;
let tv_sec = rd.read_i64::<byteorder::BigEndian>()?;
let naive = chrono::NaiveDateTime::from_timestamp(tv_sec, tv_nsec);
Ok(chrono::DateTime::<chrono::offset::Utc>::from_utc(
naive,
chrono::offset::Utc,
))
}
_ => Err(ValueReadError::TypeMismatch(marker).into()),
}
}
}
impl<'a, T, M> Factual<M> for &'a [T]
where
T: Factual<M>,
M: Mapping,
{
fn write<W: Write>(&self, mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_array_len(wr, self.len() as u32)?;
for item in *self {
item.write(mapping, wr)?;
}
Ok(())
}
fn read<R: Read>(_rd: &mut Reader<R>) -> Result<Self, Error> {
unimplemented!()
}
}
impl<T, M> Factual<M> for Vec<T>
where
T: Factual<M>,
M: Mapping,
{
fn write<W: Write>(&self, mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_array_len(wr, self.len() as u32)?;
for item in self {
item.write(mapping, wr)?;
}
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
let len = rd.read_array_len()?;
let mut res = Self::with_capacity(len);
for _ in 0..len {
res.push(T::read(rd)?);
}
Ok(res)
}
}
#[allow(clippy::implicit_hasher)]
impl<K, V, M> Factual<M> for HashMap<K, V>
where
K: Factual<M> + Hash + Eq,
V: Factual<M>,
M: Mapping,
{
fn write<W: Write>(&self, mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_map_len(wr, self.len() as u32)?;
for (k, v) in self {
k.write(mapping, wr)?;
v.write(mapping, wr)?;
}
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
let len = rd.read_map_len()?;
let mut res = Self::new();
for _ in 0..len {
res.insert(Self::subread(rd)?, Self::subread(rd)?);
}
Ok(res)
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Bin(pub Vec<u8>);
impl From<Vec<u8>> for Bin {
fn from(v: Vec<u8>) -> Self {
Self(v)
}
}
impl AsRef<[u8]> for Bin {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
impl std::ops::Deref for Bin {
type Target = [u8];
fn deref(&self) -> &[u8] {
(&self.0 as &std::ops::Deref<Target = [u8]>).deref()
}
}
use std::ops::Index;
use std::slice::SliceIndex;
impl<I> Index<I> for Bin
where
I: SliceIndex<[u8]>,
{
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
Index::index(&**self, index)
}
}
impl<M> Factual<M> for Bin
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_bin(wr, &self.0)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(Self(rd.read_bin()?))
}
}
impl<M> Factual<M> for i8
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
#[allow(clippy::cast_lossless)]
rmp::encode::write_sint(wr, *self as i64)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for i16
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
#[allow(clippy::cast_lossless)]
rmp::encode::write_sint(wr, *self as i64)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for i32
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
#[allow(clippy::cast_lossless)]
rmp::encode::write_sint(wr, *self as i64)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for i64
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_sint(wr, *self)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for u8
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
#[allow(clippy::cast_lossless)]
rmp::encode::write_uint(wr, *self as u64)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for u16
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
#[allow(clippy::cast_lossless)]
rmp::encode::write_uint(wr, *self as u64)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for u32
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
#[allow(clippy::cast_lossless)]
rmp::encode::write_uint(wr, *self as u64)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for u64
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_uint(wr, *self)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_int()?)
}
}
impl<M> Factual<M> for bool
where
M: Mapping,
{
fn write<W: Write>(&self, _mapping: &M, wr: &mut W) -> Result<(), Error> {
rmp::encode::write_bool(wr, *self)?;
Ok(())
}
fn read<R: Read>(rd: &mut Reader<R>) -> Result<Self, Error> {
Ok(rd.read_bool()?)
}
}
pub fn write<M, T, W>(t: &T, mapping: &M, wr: &mut W) -> Result<(), Error>
where
T: Factual<M>,
W: Write,
M: Mapping,
{
t.write(mapping, wr)
}
pub fn read<M, T, R>(rd: &mut Reader<R>) -> Result<T, Error>
where
T: Factual<M>,
R: Read,
M: Mapping,
{
T::read(rd)
}
impl Mapping for () {}
pub fn read_simple<T, R>(rd: &mut Reader<R>) -> Result<T, Error>
where
T: Factual<()>,
R: Read,
{
T::read(rd)
}
#[derive(Debug)]
pub struct OffsetList(pub Vec<i32>);
impl OffsetList {
#[inline]
pub fn get(&self, index: usize) -> Option<u32> {
let i = self.0[index];
if i < 0 {
None
} else {
Some(i as u32)
}
}
}
#[derive(Debug)]
pub enum TypeMapping {
Mapped(OffsetList),
Incompatible(String),
}
impl TypeMapping {
pub fn validate(&self) -> Result<&OffsetList, Error> {
use TypeMapping::*;
match self {
Mapped(list) => Ok(&list),
Incompatible(reason) => Err(Error::IncompatibleSchema(reason.to_owned())),
}
}
pub fn write<F, W>(&self, wr: &mut W, f: F) -> Result<(), Error>
where
F: Fn(&mut W, u32) -> Result<(), Error>,
W: Write,
{
let offsets = self.validate()?;
rmp::encode::write_array_len(wr, offsets.0.len() as u32)?;
for &i in &offsets.0 {
if i < 0 {
rmp::encode::write_nil(wr)?;
} else {
f(wr, i as u32)?;
}
}
Ok(())
}
pub fn write_union<W, M, T>(
&self,
wr: &mut W,
mapping: &M,
union: &'static str,
variant: &'static str,
index: usize,
value: &T,
) -> Result<(), Error>
where
T: Factual<M>,
M: Mapping,
W: Write,
{
let offsets = self.validate()?;
rmp::encode::write_array_len(wr, 2)?;
match offsets.get(index) {
Some(offset) => {
offset.write(mapping, wr)?;
value.write(mapping, wr)?;
Ok(())
}
None => Err(Error::UnwrittableUnionVariant { union, variant }),
}
}
}
pub struct SchemaInfo {
pub structs: HashMap<String, StructInfo>,
}
pub struct StructInfo {
pub fields: Vec<FieldInfo>,
}
pub struct FieldInfo {
pub name: String,
pub typ: FieldType,
}
pub enum FieldType {
Base(BaseType),
Option(Box<FieldType>),
List(Box<FieldType>),
Map(Box<FieldType>, Box<FieldType>),
}
pub enum BaseType {
I8,
I16,
I32,
I64,
U8,
U16,
U32,
U64,
F32,
F64,
Bool,
String,
Data,
Timestamp,
}
#[cfg(test)]
mod tests {
use super::{Factual, Mapping, Reader};
use netbuf::Buf;
use std::cmp::PartialEq;
use std::collections::HashMap;
use std::fmt::Debug;
#[test]
fn numbers() -> Result<(), Box<std::error::Error>> {
cycle_simple(2i8.pow(6))?;
cycle_simple(2i16.pow(14))?;
cycle_simple(2i32.pow(30))?;
cycle_simple(2i64.pow(62))?;
cycle_simple(2u8.pow(7))?;
cycle_simple(2u16.pow(15))?;
cycle_simple(2u32.pow(31))?;
cycle_simple(2u64.pow(63))?;
Ok(())
}
#[test]
fn bools() -> Result<(), Box<std::error::Error>> {
cycle_simple(true)?;
cycle_simple(false)?;
Ok(())
}
#[test]
fn strings() -> Result<(), Box<std::error::Error>> {
cycle_simple("".to_string())?;
cycle_simple("dull".repeat(128).to_string())?;
cycle_simple("dull".repeat(1024).to_string())?;
Ok(())
}
#[test]
fn timestamps() -> Result<(), Box<std::error::Error>> {
fn cycle_timestamp(
secs: i64,
nsecs: u32,
marker_expected: rmp::Marker,
) -> Result<(), Box<std::error::Error>> {
let v = chrono::NaiveDateTime::from_timestamp(secs, nsecs);
let v = chrono::DateTime::<chrono::offset::Utc>::from_utc(v, chrono::offset::Utc);
cycle_simple(v.clone())?;
let mut buf = Buf::new();
v.write(&(), &mut buf)?;
let mut slice = &buf[..];
let marker_actual = rmp::decode::read_marker(&mut slice).unwrap();
assert_eq!(marker_expected, marker_actual);
Ok(())
}
cycle_simple(chrono::offset::Utc::now())?;
cycle_timestamp(0, 0, rmp::Marker::FixExt4)?;
cycle_timestamp(1561378047, 0, rmp::Marker::FixExt4)?;
cycle_timestamp(1561378047, 2398, rmp::Marker::FixExt8)?;
cycle_timestamp(7273195896, 0, rmp::Marker::FixExt8)?;
cycle_timestamp(7273195896, 23549, rmp::Marker::FixExt8)?;
cycle_timestamp(-14182980, 0, rmp::Marker::Ext8)?;
cycle_timestamp(19898323200, 0, rmp::Marker::Ext8)?;
cycle_timestamp(19898323200, 2359807, rmp::Marker::Ext8)?;
Ok(())
}
#[test]
fn arrays() -> Result<(), Box<std::error::Error>> {
let strings = vec!["foo".to_string(), "bar".to_string(), "dull".repeat(128)];
cycle_simple(strings)?;
Ok(())
}
#[test]
fn maps() -> Result<(), Box<std::error::Error>> {
let mut map = HashMap::<String, i32>::new();
cycle_simple(map.clone())?;
map.insert("ten".into(), 10);
map.insert("twenty eight".into(), 28);
map.insert("one hundred and thirty nine".into(), 139);
cycle_simple(map.clone())?;
Ok(())
}
#[test]
fn bins() -> Result<(), Box<std::error::Error>> {
let bin: Vec<u8> = vec![];
cycle_simple(super::Bin(bin))?;
let bin: Vec<u8> = vec![6, 123, 92, 32, 41, 0, 14, 28, 255];
cycle_simple(super::Bin(bin))?;
let mut bin: Vec<u8> = Vec::new();
for _ in 0..1024 {
bin.push(6);
bin.push(92);
bin.push(0);
bin.push(32);
}
assert_eq!(92, bin[1]);
bin[1] = 93;
assert_eq!(&[6, 93], &bin[0..2]);
cycle_simple(super::Bin(bin))?;
Ok(())
}
fn cycle_simple<T>(l: T) -> Result<(), Box<std::error::Error>>
where
T: Factual<()> + Debug + PartialEq,
{
cycle((), l)
}
fn cycle<T, M>(mapping: M, l: T) -> Result<(), Box<std::error::Error>>
where
T: Factual<M> + Debug + PartialEq,
M: Mapping,
{
let mut buf = Buf::new();
l.write(&mapping, &mut buf)?;
let mut slice = &buf[..];
let r: T = super::read(&mut Reader::new(&mut slice))?;
assert_eq!(l, r);
Ok(())
}
}