use crate::result::ArchiveResult; use std::io::{Read, Write}; pub trait ArchiveDatatype where Self: Sized, { const SIZE: usize; fn read(reader: impl Read) -> ArchiveResult; fn write(&self, writer: impl Write) -> ArchiveResult<()>; } pub mod utils { pub fn read_string(buf: &[u8]) -> String { String::from_utf8(buf.into()).unwrap() } pub fn write_string(string: &str) -> &[u8] { string.as_bytes() } pub fn vec(vec: &[u8]) -> &[u8] { vec } #[macro_export] macro_rules! create_archive_datatype { { $vis:vis struct $struct_name:ident { $($field:ident: $field_type:ty,)* } $( let $custom_field:ident: $custom_field_type:ty { size: $custom_field_size: expr, read: $custom_field_read: path, write: $custom_field_write: path, } )* $( const { $($const_name:ident: $const_type:ty = $const_value:expr;)+ } )? $( read $read_code:block )? $( write $write_code:block )? } => { #[derive(Debug)] $vis struct $struct_name { $($vis $field: $field_type),*, $($vis $custom_field: $custom_field_type),* } $( impl $struct_name { $(const $const_name: $const_type = $const_value;)* } )? impl ArchiveDatatype for $struct_name { const SIZE: usize = ($((<$field_type>::BITS / 8)+)*0) as usize; fn read(mut reader: impl Read) -> ArchiveResult { let mut buf = [0; Self::SIZE]; reader.read(&mut buf)?; $( let (bytes, buf) = buf.split_at((<$field_type>::BITS / 8) as usize); let $field = <$field_type>::from_le_bytes(bytes.try_into().unwrap()); )* $( let $custom_field = { let mut buf = vec![0; $custom_field_size as usize]; reader.read(&mut buf)?; $custom_field_read(&buf).into() }; )* #[allow(dropping_references)] drop(buf); $($read_code;)? Ok( Self { $($field),*, $($custom_field),* } ) } fn write(&self, mut writer: impl Write) -> ArchiveResult<()> { $($write_code;)? writer.write(&[ $(&self.$field.to_le_bytes()[..]),*, $(&$custom_field_write(&self.$custom_field)),* ].concat())?; Ok(()) } } }; } pub use create_archive_datatype; }