use crate::error;
use ark_std::{
io::{Read, Result as IoResult, Write},
vec::Vec,
};
pub trait ToBytes {
fn write<W: Write>(&self, writer: W) -> IoResult<()>;
}
pub trait FromBytes: Sized {
fn read<R: Read>(reader: R) -> IoResult<Self>;
}
impl<const N: usize> ToBytes for [u8; N] {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
writer.write_all(self)
}
}
impl<const N: usize> FromBytes for [u8; N] {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut arr = [0u8; N];
reader.read_exact(&mut arr)?;
Ok(arr)
}
}
impl<const N: usize> ToBytes for [u16; N] {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
for num in self {
writer.write_all(&num.to_le_bytes())?;
}
Ok(())
}
}
impl<const N: usize> FromBytes for [u16; N] {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut res = [0u16; N];
for num in res.iter_mut() {
let mut bytes = [0u8; 2];
reader.read_exact(&mut bytes)?;
*num = u16::from_le_bytes(bytes);
}
Ok(res)
}
}
impl<const N: usize> ToBytes for [u32; N] {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
for num in self {
writer.write_all(&num.to_le_bytes())?;
}
Ok(())
}
}
impl<const N: usize> FromBytes for [u32; N] {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut res = [0u32; N];
for num in res.iter_mut() {
let mut bytes = [0u8; 4];
reader.read_exact(&mut bytes)?;
*num = u32::from_le_bytes(bytes);
}
Ok(res)
}
}
impl<const N: usize> ToBytes for [u64; N] {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
for num in self {
writer.write_all(&num.to_le_bytes())?;
}
Ok(())
}
}
impl<const N: usize> FromBytes for [u64; N] {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut res = [0u64; N];
for num in res.iter_mut() {
let mut bytes = [0u8; 8];
reader.read_exact(&mut bytes)?;
*num = u64::from_le_bytes(bytes);
}
Ok(res)
}
}
impl<const N: usize> ToBytes for [u128; N] {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
for num in self {
writer.write_all(&num.to_le_bytes())?;
}
Ok(())
}
}
impl<const N: usize> FromBytes for [u128; N] {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut res = [0u128; N];
for num in res.iter_mut() {
let mut bytes = [0u8; 16];
reader.read_exact(&mut bytes)?;
*num = u128::from_le_bytes(bytes);
}
Ok(res)
}
}
#[macro_export]
macro_rules! to_bytes {
($($x:expr),*) => ({
let mut buf = $crate::vec![];
{$crate::push_to_vec!(buf, $($x),*)}.map(|_| buf)
});
}
#[macro_export]
macro_rules! push_to_vec {
($buf:expr, $y:expr, $($x:expr),*) => ({
{
$crate::ToBytes::write(&$y, &mut $buf)
}.and({$crate::push_to_vec!($buf, $($x),*)})
});
($buf:expr, $x:expr) => ({
$crate::ToBytes::write(&$x, &mut $buf)
})
}
impl ToBytes for u8 {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
writer.write_all(&[*self])
}
}
impl FromBytes for u8 {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut byte = [0u8];
reader.read_exact(&mut byte)?;
Ok(byte[0])
}
}
impl ToBytes for u16 {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
writer.write_all(&self.to_le_bytes())
}
}
impl FromBytes for u16 {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut bytes = [0u8; 2];
reader.read_exact(&mut bytes)?;
Ok(u16::from_le_bytes(bytes))
}
}
impl ToBytes for u32 {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
writer.write_all(&self.to_le_bytes())
}
}
impl FromBytes for u32 {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut bytes = [0u8; 4];
reader.read_exact(&mut bytes)?;
Ok(u32::from_le_bytes(bytes))
}
}
impl ToBytes for u64 {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
writer.write_all(&self.to_le_bytes())
}
}
impl FromBytes for u64 {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut bytes = [0u8; 8];
reader.read_exact(&mut bytes)?;
Ok(u64::from_le_bytes(bytes))
}
}
impl ToBytes for u128 {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
writer.write_all(&self.to_le_bytes())
}
}
impl FromBytes for u128 {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let mut bytes = [0u8; 16];
reader.read_exact(&mut bytes)?;
Ok(u128::from_le_bytes(bytes))
}
}
impl ToBytes for () {
#[inline]
fn write<W: Write>(&self, _writer: W) -> IoResult<()> {
Ok(())
}
}
impl FromBytes for () {
#[inline]
fn read<R: Read>(_bytes: R) -> IoResult<Self> {
Ok(())
}
}
impl ToBytes for bool {
#[inline]
fn write<W: Write>(&self, writer: W) -> IoResult<()> {
u8::write(&(*self as u8), writer)
}
}
impl FromBytes for bool {
#[inline]
fn read<R: Read>(reader: R) -> IoResult<Self> {
match u8::read(reader) {
Ok(0) => Ok(false),
Ok(1) => Ok(true),
Ok(_) => Err(error("FromBytes::read failed")),
Err(err) => Err(err),
}
}
}
impl<T: ToBytes> ToBytes for Vec<T> {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
for item in self {
item.write(&mut writer)?;
}
Ok(())
}
}
impl<'a, T: 'a + ToBytes> ToBytes for &'a [T] {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
for item in *self {
item.write(&mut writer)?;
}
Ok(())
}
}
impl<'a, T: 'a + ToBytes> ToBytes for &'a T {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
(*self).write(&mut writer)
}
}
impl<T: ToBytes> ToBytes for Option<T> {
#[inline]
fn write<W: Write>(&self, mut writer: W) -> IoResult<()> {
if let Some(val) = self {
true.write(&mut writer)?;
val.write(&mut writer)
} else {
false.write(&mut writer)
}
}
}
impl<T: FromBytes> FromBytes for Option<T> {
#[inline]
fn read<R: Read>(mut reader: R) -> IoResult<Self> {
let is_some = bool::read(&mut reader)?;
if is_some {
T::read(&mut reader).map(Some)
} else {
Ok(None)
}
}
}
#[cfg(test)]
mod test {
use ark_std::vec::Vec;
#[test]
fn test_macro_empty() {
let array: Vec<u8> = vec![];
let bytes: Vec<u8> = to_bytes![array].unwrap();
assert_eq!(&bytes, &[]);
assert_eq!(bytes.len(), 0);
}
#[test]
fn test_macro() {
let array1 = [1u8; 32];
let array2 = [2u8; 16];
let array3 = [3u8; 8];
let bytes = to_bytes![array1, array2, array3].unwrap();
assert_eq!(bytes.len(), 56);
let mut actual_bytes = Vec::new();
actual_bytes.extend_from_slice(&array1);
actual_bytes.extend_from_slice(&array2);
actual_bytes.extend_from_slice(&array3);
assert_eq!(bytes, actual_bytes);
}
}