I implemented BinaryConverter
trait that provides me methods to read from/into buffer:
pub trait BinaryConverter {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error>;
fn read_from<R: BufRead>(&mut self, reader: R) -> Result<Self, Error> where Self: Sized;
}
Next I implemented it on each type I want to use with. But the issue there is that impl not work for Vec and I got next error on compile:
error[E0277]: the trait bound `Vec<u8>: BufRead` is not satisfied
--> src/main.rs:183:55
|
183 | $field_name: self.$field_name.read_from(&mut buffer).unwrap(),
| ^^^^^^^^^ the trait `BufRead` is not implemented for `Vec<u8>`
...
193 | / packet! {
194 | | properties {
195 | | opcode 100;
196 | | size: u16;
... |
205 | | }
206 | | }
| |_____- in this macro invocation
|
= help: the following other types implement trait `BufRead`:
&[u8]
&mut B
Box<B>
BufReader<R>
StdinLock<'_>
std::io::Chain<T, U>
std::io::Cursor<T>
std::io::Empty
std::io::Take<T>
= note: required because of the requirements on the impl of `BufRead` for `&mut Vec<u8>`
note: required by a bound in `BinaryConverter::read_from`
--> src/main.rs:6:21
|
6 | fn read_from<R: BufRead>(&mut self, reader: R) -> Result<Self, Error> where Self: Sized;
| ^^^^^^^ required by this bound in `BinaryConverter::read_from`
= note: this error originates in the macro `packet` (in Nightly builds, run with -Z macro-backtrace for more info)
First of all, I want to mention, I did impl on Vec<u8>
instead of fixed sized array, because I am not sure how to do this. So each time I faced with smth like [u8; 10] I do .to_vec()
call on it.
But, anyway, I still need both: Vec and fixed sized array.
Now, this is full example of my trait:
pub trait BinaryConverter {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error>;
fn read_from<R: BufRead>(&mut self, reader: R) -> Result<Self, Error> where Self: Sized;
}
impl BinaryConverter for u8 {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error> {
buffer.write_u8(*self)
}
fn read_from<R: BufRead>(&mut self, mut reader: R) -> Result<u8, Error> {
reader.read_u8()
}
}
impl BinaryConverter for u16 {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error> {
buffer.write_u16::<LittleEndian>(*self)
}
fn read_from<R: BufRead>(&mut self, mut reader: R) -> Result<u16, Error> {
reader.read_u16::<LittleEndian>()
}
}
impl BinaryConverter for u32 {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error> {
buffer.write_u32::<LittleEndian>(*self)
}
fn read_from<R: BufRead>(&mut self, mut reader: R) -> Result<u32, Error> {
reader.read_u32::<LittleEndian>()
}
}
impl BinaryConverter for u64 {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error> {
buffer.write_u64::<LittleEndian>(*self)
}
fn read_from<R: BufRead>(&mut self, mut reader: R) -> Result<u64, Error> {
reader.read_u64::<LittleEndian>()
}
}
impl BinaryConverter for String {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error> {
buffer.write_all(&self.to_string().into_bytes())
}
fn read_from<R: BufRead>(&mut self, mut reader: R) -> Result<String, Error> {
let mut internal_buf = vec![];
reader.read_until(0, &mut internal_buf)?;
match String::from_utf8(internal_buf) {
Ok(string) => Ok(string),
Err(err) => Err(Error::new(ErrorKind::Other, err.to_string())),
}
}
}
impl BinaryConverter for Vec<u8> {
fn read_into(&mut self, buffer: &mut Vec<u8>) -> Result<(), Error> {
buffer.write_all(self)
}
fn read_from<R: BufRead>(&mut self, mut reader: R) -> Result<Vec<u8>, Error> {
let mut internal_buf = vec![];
reader.read_exact(&mut internal_buf)?;
Ok(internal_buf)
}
}
I use it in my macro, that generates structs like below:
packet! {
properties {
opcode 100;
size: u16;
}
#[derive(Hash)]
pub struct Outcome {
name: String,
os: u8,
version: u32,
game_name: String,
}
}
let mut packet = Outcome {
name: String::from("Some name"),
os: 1,
version: 9,
game_name: String::from("Game"),
};
This is my macro:
macro_rules! packet {
// first rule
(
properties {
$(opcode $opcode_value:expr;)?
}
$(#[$outer:meta])*
$vis:vis struct $PacketStruct:ident {
$($field_name:ident: $field_type:ty),*$(,)?
}
$($StructImpl: item)*
) => {
$(#[$outer])*
#[derive(Clone)]
$vis struct $PacketStruct {
$($field_name: $field_type),*
}
$($StructImpl)*
$(
impl $PacketStruct {
pub fn get_opcode() -> u32 {
$opcode_value
}
}
)?
impl $PacketStruct {
pub fn to_binary(&mut self) -> Vec<u8> {
let mut packet = Vec::new();
$(
self.$field_name.read_into(&mut packet);
)*;
packet
}
}
};
// eof first rule
// second rule
(
properties {
opcode $opcode_value:expr;
$($prop_name:ident: $prop_type:ty;)*
}
$(#[$outer:meta])*
$vis:vis struct $PacketStruct:ident {
$($field_name:ident: $field_type:ty),*$(,)?
}
$($StructImpl: item)*
) => {
packet! {
properties {
$($prop_name: $prop_type;)*
}
$(#[$outer])*
$vis struct $PacketStruct {
$($field_name: $field_type),*
}
$($StructImpl)*
impl $PacketStruct {
pub fn get_opcode() -> u32 {
$opcode_value
}
}
}
};
// eof of second rule
// third rule
(
properties {
$($prop_name:ident: $prop_type:ty;)*
}
$(#[$outer:meta])*
$vis:vis struct $PacketStruct:ident {
$($field_name:ident: $field_type:ty),*$(,)?
}
$($StructImpl: item)*
) => {
$(#[$outer])*
#[derive(Clone)]
$vis struct $PacketStruct {
$($field_name: $field_type),*
}
$($StructImpl)*
impl $PacketStruct {
pub fn to_binary(&mut self) -> Vec<u8> {
let mut packet = Vec::new();
$(
self.$field_name.read_into(&mut packet);
)*
packet
}
pub fn from_binary(&mut self, buffer: Vec<u8>) -> $PacketStruct {
$PacketStruct {
$(
$field_name: self.$field_name.read_from(&mut buffer).unwrap(),
)*
}
}
}
};
}
Could somebody explain, how to fix the issue and how to implement this trait on fixed sized array ?