init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
21
Cargo.toml
Normal file
21
Cargo.toml
Normal file
@@ -0,0 +1,21 @@
|
||||
[workspace]
|
||||
members = ["derive_macro"]
|
||||
|
||||
[package]
|
||||
name = "otw"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
|
||||
|
||||
[features]
|
||||
default = ["alloc", "extra-validation"]
|
||||
|
||||
extra-validation = []
|
||||
alloc = []
|
||||
std = []
|
||||
|
||||
|
||||
[dependencies]
|
||||
derive_macro = { path = "derive_macro" }
|
||||
e = { git = "https://git.intege.rs/xlib/e.git" }
|
||||
13
derive_macro/Cargo.toml
Normal file
13
derive_macro/Cargo.toml
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "derive_macro"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
syn = { version = "2.0.101", features = ["full", "extra-traits"] }
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1"
|
||||
|
||||
139
derive_macro/src/lib.rs
Normal file
139
derive_macro/src/lib.rs
Normal file
@@ -0,0 +1,139 @@
|
||||
#![feature(try_blocks)]
|
||||
|
||||
use proc_macro::TokenStream;
|
||||
use std::fmt::Write;
|
||||
use proc_macro2::Ident;
|
||||
use quote::ToTokens;
|
||||
use syn::{Data, DataStruct, DeriveInput, Fields, parse_macro_input};
|
||||
|
||||
#[proc_macro_derive(OverTheWire)]
|
||||
pub fn derive_bin_serializer(input: TokenStream) -> TokenStream {
|
||||
let input = parse_macro_input!(input as DeriveInput);
|
||||
|
||||
match input.data {
|
||||
Data::Struct(data) => { derive_struct(input.ident, &data).unwrap() }
|
||||
Data::Enum(_data) => { panic!("Cannot derive OverTheWire for Enums (yet)"); }
|
||||
Data::Union(_data) => { panic!("Cannot derive OverTheWire for Unions"); }
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused_variables)]
|
||||
fn derive_struct(name: Ident, data: &DataStruct) -> Result<TokenStream, std::fmt::Error> {
|
||||
let mut output = String::new();
|
||||
|
||||
// collect the fields...
|
||||
let input_fields = match &data.fields {
|
||||
|
||||
// field_name: <value>
|
||||
Fields::Named(fields) =>
|
||||
fields.named.iter().filter_map(
|
||||
|n| { n.ident.as_ref().map(|i| i.to_string()) }
|
||||
).collect::<Vec<String>>(),
|
||||
|
||||
// field names are 0, 1, 2, etc.
|
||||
Fields::Unnamed(fields) =>
|
||||
(0..fields.unnamed.len())
|
||||
.map(|i| i.to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
|
||||
// no fields to worry about
|
||||
Fields::Unit => Vec::new(),
|
||||
};
|
||||
|
||||
|
||||
const PAD: &str = " ";
|
||||
let deserialize = match &data.fields {
|
||||
Fields::Named(_) => {
|
||||
let mut output = String::new();
|
||||
writeln!(&mut output, "{PAD}Ok(Self{{")?;
|
||||
for fname in &input_fields {
|
||||
writeln!(&mut output, "{PAD} {fname}: otw::OverTheWire::deserialize(reader)?,")?
|
||||
}
|
||||
writeln!(&mut output, "{PAD}}})")?;
|
||||
output
|
||||
}
|
||||
|
||||
Fields::Unnamed(_) => {
|
||||
let mut output = String::new();
|
||||
writeln!(&mut output, "{PAD}Ok(Self(")?;
|
||||
for fname in &input_fields {
|
||||
writeln!(&mut output, "{PAD} otw::OverTheWire::deserialize(reader)?,")?
|
||||
}
|
||||
writeln!(&mut output, "{PAD}))")?;
|
||||
output
|
||||
}
|
||||
|
||||
Fields::Unit => "Ok(Self)".to_string(),
|
||||
};
|
||||
|
||||
let serialize = match data.fields {
|
||||
Fields::Named(_) | Fields::Unnamed(_) => {
|
||||
let mut output = String::new();
|
||||
for fname in &input_fields {
|
||||
writeln!(&mut output, "{PAD}self.{fname}.serialize(writer)?;")?
|
||||
}
|
||||
writeln!(&mut output, "{PAD}Ok(())")?;
|
||||
output
|
||||
}
|
||||
Fields::Unit => "Ok(())".to_string(),
|
||||
};
|
||||
|
||||
|
||||
let input_types = match &data.fields {
|
||||
|
||||
// field_name: <value>
|
||||
Fields::Named(fields) =>
|
||||
fields.named.iter()
|
||||
.map(|n| { n.ty.to_token_stream().to_string() })
|
||||
.collect::<Vec<String>>(),
|
||||
|
||||
// field names are 0, 1, 2, etc.
|
||||
Fields::Unnamed(fields) => fields.unnamed.iter()
|
||||
.map(|f|f.ty.to_token_stream().to_string())
|
||||
.collect::<Vec<String>>(),
|
||||
|
||||
// no fields to worry about
|
||||
Fields::Unit => Vec::new(),
|
||||
};
|
||||
|
||||
|
||||
let size_hint = match data.fields {
|
||||
Fields::Named(_) | Fields::Unnamed(_) => {
|
||||
let mut output = String::new();
|
||||
writeln!(&mut output, "{PAD}0usize")?;
|
||||
for ftype in &input_types {
|
||||
writeln!(&mut output, "{PAD} .saturating_add(otw::min_wire_size::<{ftype}>())")?
|
||||
}
|
||||
output
|
||||
}
|
||||
Fields::Unit => "Ok(())".to_string(),
|
||||
};
|
||||
|
||||
writeln!(&mut output, "#[automatically_derived]")?;
|
||||
writeln!(&mut output, "impl otw::OverTheWire for {name} {{")?;
|
||||
writeln!(&mut output, " fn serialize<T: otw::Writer>(&self, writer: &mut T) -> e::Result<()> {{")?;
|
||||
writeln!(&mut output, "{serialize}")?;
|
||||
writeln!(&mut output, " }}")?;
|
||||
writeln!(&mut output, " fn deserialize<T: otw::Reader>(reader: &mut T) -> e::Result<Self> {{")?;
|
||||
writeln!(&mut output, "{deserialize}")?;
|
||||
writeln!(&mut output, " }}")?;
|
||||
writeln!(&mut output, " fn size_hint() -> usize {{")?;
|
||||
writeln!(&mut output, "{size_hint}")?;
|
||||
writeln!(&mut output, " }}")?;
|
||||
|
||||
|
||||
/*
|
||||
fn size_hint() -> usize {
|
||||
size_of::<Self>()
|
||||
}
|
||||
*/
|
||||
|
||||
writeln!(&mut output, "}}")?;
|
||||
|
||||
|
||||
if let Err(error) = output.parse::<TokenStream>() {
|
||||
panic!("{}", output);
|
||||
}
|
||||
|
||||
Ok(output.parse().unwrap())
|
||||
}
|
||||
173
src/impls/lib_alloc.rs
Normal file
173
src/impls/lib_alloc.rs
Normal file
@@ -0,0 +1,173 @@
|
||||
use crate::{MalformedData, OverTheWire, Reader, Writer};
|
||||
|
||||
use alloc::{
|
||||
|
||||
// heap ptr's
|
||||
boxed::Box,
|
||||
sync::Arc,
|
||||
rc::Rc,
|
||||
|
||||
// collections
|
||||
collections::BTreeMap,
|
||||
string::String,
|
||||
vec::Vec,
|
||||
|
||||
};
|
||||
|
||||
|
||||
impl<OTW: OverTheWire> OverTheWire for Box<OTW> {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
OTW::serialize(&*self, writer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
Ok(Box::new(OTW::deserialize(reader)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint() -> usize {
|
||||
OTW::size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl<OTW: OverTheWire> OverTheWire for Rc<OTW> {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
OTW::serialize(&*self, writer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
Ok(Rc::new(OTW::deserialize(reader)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint() -> usize {
|
||||
OTW::size_hint()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<OTW: OverTheWire> OverTheWire for Arc<OTW> {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
OTW::serialize(&*self, writer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
Ok(Arc::new(OTW::deserialize(reader)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint() -> usize {
|
||||
OTW::size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl OverTheWire for String {
|
||||
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
(self.len() as u32).serialize(writer)?;
|
||||
writer.write(self.as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
let len = u32::deserialize(reader)?;
|
||||
|
||||
#[cfg(feature = "extra-validation")]
|
||||
if len as usize > reader.remainder_hint() {
|
||||
return Err(MalformedData)?;
|
||||
}
|
||||
|
||||
let mut vec = Vec::with_capacity(len as usize);
|
||||
unsafe { vec.set_len(len as usize) };
|
||||
reader.read(vec.as_mut_slice())?;
|
||||
|
||||
let s = String::from_utf8(vec)
|
||||
.map_err(|_|MalformedData)?;
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
fn size_hint() -> usize {
|
||||
u32::size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl <OTW: OverTheWire> OverTheWire for Vec<OTW> {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
(self.len() as u32).serialize(writer)?;
|
||||
for v in self {
|
||||
v.serialize(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
let len = u32::deserialize(reader)?;
|
||||
|
||||
#[cfg(feature = "extra-validation")]
|
||||
if OTW::size_hint().saturating_mul(len as usize) > reader.remainder_hint() {
|
||||
return Err(MalformedData)?;
|
||||
}
|
||||
|
||||
let mut buffer = Vec::with_capacity(len as usize);
|
||||
for _ in 0..len {
|
||||
buffer.push(OTW::deserialize(reader)?);
|
||||
}
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn size_hint() -> usize {
|
||||
u32::size_hint()
|
||||
}
|
||||
}
|
||||
|
||||
impl <K: OverTheWire + Ord, V: OverTheWire> OverTheWire for BTreeMap<K,V> {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
(self.len() as u32).serialize(writer)?;
|
||||
for (k,v) in self {
|
||||
k.serialize(writer)?;
|
||||
v.serialize(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
let len = u32::deserialize(reader)?;
|
||||
|
||||
|
||||
#[cfg(feature = "extra-validation")]
|
||||
if K::size_hint()
|
||||
.saturating_add(V::size_hint())
|
||||
.saturating_mul(len as usize) > reader.remainder_hint() {
|
||||
return Err(MalformedData)?;
|
||||
}
|
||||
|
||||
let mut buffer = BTreeMap::<K,V>::new();
|
||||
for _ in 0..len {
|
||||
let k = K::deserialize(reader)?;
|
||||
let v = V::deserialize(reader)?;
|
||||
buffer.insert(k,v);
|
||||
}
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
fn size_hint() -> usize {
|
||||
u32::size_hint()
|
||||
}
|
||||
}
|
||||
42
src/impls/lib_std.rs
Normal file
42
src/impls/lib_std.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use crate::{MalformedData, OverTheWire, Reader, Writer};
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
impl <K: OverTheWire + Hash + Eq, V: OverTheWire> OverTheWire for HashMap<K,V> {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
(self.len() as u32).serialize(writer)?;
|
||||
for (k,v) in self {
|
||||
k.serialize(writer)?;
|
||||
v.serialize(writer)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
let len = u32::deserialize(reader)?;
|
||||
|
||||
|
||||
#[cfg(feature = "extra-validation")]
|
||||
if K::size_hint()
|
||||
.saturating_add(V::size_hint())
|
||||
.saturating_mul(len as usize) > reader.remainder_hint() {
|
||||
return Err(MalformedData)?;
|
||||
}
|
||||
|
||||
let mut buffer = HashMap::<K,V>::new();
|
||||
for _ in 0..len {
|
||||
let k = K::deserialize(reader)?;
|
||||
let v = V::deserialize(reader)?;
|
||||
buffer.insert(k,v);
|
||||
}
|
||||
Ok(buffer)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn size_hint() -> usize {
|
||||
u32::size_hint()
|
||||
}
|
||||
}
|
||||
27
src/impls/magic.rs
Normal file
27
src/impls/magic.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use crate::{MalformedData, OverTheWire, Reader, Writer};
|
||||
|
||||
|
||||
/// Zero-sized type that is written as a 4-byte magic number used for validation
|
||||
pub struct Magic<const VALUE: u32>;
|
||||
|
||||
impl<const V: u32> OverTheWire for Magic<V> {
|
||||
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
writer.write(V.to_le_bytes().as_slice())
|
||||
}
|
||||
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
let _read = u32::from_le_bytes(reader.bytes::<4>()?);
|
||||
|
||||
#[cfg(feature = "extra-validation")]
|
||||
if _read != V { return Err(MalformedData)? }
|
||||
|
||||
Ok(Self)
|
||||
}
|
||||
|
||||
fn size_hint() -> usize {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
129
src/impls/primitives.rs
Normal file
129
src/impls/primitives.rs
Normal file
@@ -0,0 +1,129 @@
|
||||
use crate::{OverTheWire, Reader, Writer};
|
||||
|
||||
//╶───╴Numbers╶──────────────────────────────────────────────────────────────╴
|
||||
|
||||
macro_rules! impl_integer {
|
||||
($($t:ty),+) => {
|
||||
$(impl OverTheWire for $t {
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
writer.write(self.to_le_bytes().as_slice())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
Ok(Self::from_le_bytes(reader.bytes()?))
|
||||
}
|
||||
|
||||
fn size_hint() -> usize {
|
||||
size_of::<Self>()
|
||||
}
|
||||
|
||||
})+
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
impl_integer!(u8, u16, u32, u64, u128);
|
||||
impl_integer!(i8, i16, i32, i64, i128);
|
||||
impl_integer!(f32, f64);
|
||||
|
||||
//╶───╴Boolean╶──────────────────────────────────────────────────────────────╴
|
||||
|
||||
/// Implement for booleans
|
||||
impl OverTheWire for bool {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
writer.write(&[*self as u8])
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
Ok(reader.bytes::<1>()?[0] != 0)
|
||||
}
|
||||
|
||||
fn size_hint() -> usize { 1 }
|
||||
}
|
||||
|
||||
/// Implement for unit types...
|
||||
impl OverTheWire for () {
|
||||
fn serialize<T: Writer>(&self, _: &mut T) -> e::Result<()> { Ok(()) }
|
||||
fn deserialize<T: Reader>(_: &mut T) -> e::Result<Self> { Ok(()) }
|
||||
fn size_hint() -> usize { 0 }
|
||||
}
|
||||
|
||||
//╶───╴Arrays╶───────────────────────────────────────────────────────────────╴
|
||||
|
||||
impl<const S: usize, OTW: OverTheWire> OverTheWire for [OTW; S] {
|
||||
|
||||
#[inline]
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
for i in self {
|
||||
i.serialize(writer)?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
let mut array = core::mem::MaybeUninit::<[OTW; S]>::uninit();
|
||||
|
||||
for i in 0..S {
|
||||
match OTW::deserialize(reader) {
|
||||
Ok(v) => unsafe {
|
||||
// assign the value directly into the uninit array...
|
||||
*array.as_mut_ptr().cast::<OTW>().add(i) = v;
|
||||
}
|
||||
Err(error) => unsafe {
|
||||
|
||||
// drop only the value's that were assigned
|
||||
for i in 0..i {
|
||||
core::ptr::drop_in_place(array.as_mut_ptr().cast::<OTW>().add(i))
|
||||
}
|
||||
|
||||
// forward the error
|
||||
return Err(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(unsafe { array.assume_init() })
|
||||
}
|
||||
|
||||
fn size_hint() -> usize {
|
||||
OTW::size_hint().saturating_mul(S)
|
||||
}
|
||||
}
|
||||
|
||||
//╶───╴Tuples╶───────────────────────────────────────────────────────────────╴
|
||||
|
||||
macro_rules! impl_tuple {
|
||||
( $($t:ident : $l:tt),+ ) => {
|
||||
impl < $($t: OverTheWire),+ > OverTheWire for ($($t),+, ) {
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()> {
|
||||
$(self.$l.serialize(writer)?;)+
|
||||
Ok(())
|
||||
}
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self> {
|
||||
Ok((
|
||||
$($t::deserialize(reader)?),+,
|
||||
))
|
||||
}
|
||||
fn size_hint() -> usize {
|
||||
0usize $( .saturating_add($t::size_hint()) )+
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_tuple!( K0:0 );
|
||||
impl_tuple!( K0:0, K1:1 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3, K4:4 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3, K4:4, K5:5 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3, K4:4, K5:5, K6:6 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3, K4:4, K5:5, K6:6, K7:7 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3, K4:4, K5:5, K6:6, K7:7, K8:8 );
|
||||
impl_tuple!( K0:0, K1:1, K2:2, K3:3, K4:4, K5:5, K6:6, K7:7, K8:8, K9:9 );
|
||||
76
src/lib.rs
Normal file
76
src/lib.rs
Normal file
@@ -0,0 +1,76 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
/*
|
||||
TODO - Future Improvements
|
||||
implement var-int support for length & integers
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
extern crate alloc;
|
||||
|
||||
//╶───╴Modules╶──────────────────────────────────────────────────────────────╴
|
||||
|
||||
mod impls {
|
||||
|
||||
mod primitives;
|
||||
|
||||
mod magic;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
mod lib_alloc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
mod lib_std;
|
||||
|
||||
}
|
||||
|
||||
|
||||
mod streams;
|
||||
|
||||
|
||||
//╶───╴Core Traits╶──────────────────────────────────────────────────────────╴
|
||||
|
||||
e::new_exception!(MalformedData);
|
||||
|
||||
pub trait Writer {
|
||||
fn write(&mut self, bytes: &[u8]) -> e::Result<()>;
|
||||
}
|
||||
|
||||
pub trait Reader {
|
||||
fn read(&mut self, bytes: &mut [u8]) -> e::Result<()>;
|
||||
|
||||
#[inline(always)]
|
||||
fn bytes<const S: usize>(&mut self) -> e::Result<[u8;S]> {
|
||||
Ok(unsafe {
|
||||
let mut buffer = core::mem::MaybeUninit::<[u8;S]>::uninit();
|
||||
self.read(buffer.assume_init_mut().as_mut_slice())?;
|
||||
buffer.assume_init()
|
||||
})
|
||||
}
|
||||
|
||||
/// used for validating large arrays of data...
|
||||
fn remainder_hint(&self) -> usize;
|
||||
|
||||
}
|
||||
|
||||
pub use derive_macro::OverTheWire;
|
||||
|
||||
pub trait OverTheWire: Sized {
|
||||
fn serialize<T: Writer>(&self, writer: &mut T) -> e::Result<()>;
|
||||
fn deserialize<T: Reader>(reader: &mut T) -> e::Result<Self>;
|
||||
|
||||
/// the minimum size of this type, used for extra validation
|
||||
fn size_hint() -> usize;
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn min_wire_size<T: OverTheWire>() -> usize {
|
||||
T::size_hint()
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
33
src/streams.rs
Normal file
33
src/streams.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use crate::{MalformedData, Reader, Writer};
|
||||
|
||||
impl Reader for &[u8] {
|
||||
|
||||
#[inline(always)]
|
||||
fn read(&mut self, bytes: &mut [u8]) -> e::Result<()> {
|
||||
if bytes.len() > self.len() { Err(MalformedData)? }
|
||||
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(
|
||||
self.as_ptr(),
|
||||
bytes.as_mut_ptr(),
|
||||
bytes.len()
|
||||
)
|
||||
}
|
||||
|
||||
*self = &self[bytes.len()..];
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn remainder_hint(&self) -> usize {
|
||||
self.len()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Writer for alloc::vec::Vec<u8> {
|
||||
fn write(&mut self, bytes: &[u8]) -> e::Result<()> {
|
||||
self.extend_from_slice(bytes);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user