Skip to content

Commit

Permalink
Split FromBytes and ToBytes into a base and an extension trait
Browse files Browse the repository at this point in the history
  • Loading branch information
vE5li committed Feb 21, 2024
1 parent 7ef3123 commit 8b05a9a
Show file tree
Hide file tree
Showing 19 changed files with 411 additions and 504 deletions.
42 changes: 19 additions & 23 deletions procedural/src/byte/convertable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ fn derive_for_struct(
_ => panic!(),
};

let from = implement_from.then(|| quote! {
impl #impl_generics crate::loaders::FromBytes for #name #type_generics #where_clause {
fn from_bytes(byte_stream: &mut crate::loaders::ByteStream, length_hint: Option<usize>) -> Result<Self, Box<crate::loaders::ConversionError>> {
crate::loaders::check_length_hint_none::<Self>(length_hint)?;

let base_offset = byte_stream.get_offset();
#(#from_bytes_implementations)*
Ok(#instanciate)
let from = implement_from.then(|| {
quote! {
impl #impl_generics crate::loaders::FromBytes for #name #type_generics #where_clause {
fn from_bytes(byte_stream: &mut crate::loaders::ByteStream) -> Result<Self, Box<crate::loaders::ConversionError>> {
let base_offset = byte_stream.get_offset();
#(#from_bytes_implementations)*
Ok(#instanciate)
}
}
}
});
Expand All @@ -39,9 +39,7 @@ fn derive_for_struct(
impl #impl_generics crate::loaders::ToBytes for #name #type_generics #where_clause {
// Temporary until serialization is always possible
#[allow(unreachable_code)]
fn to_bytes(&self, length_hint: Option<usize>) -> Result<Vec<u8>, Box<crate::loaders::ConversionError>> {
crate::loaders::check_length_hint_none::<Self>(length_hint)?;

fn to_bytes(&self) -> Result<Vec<u8>, Box<crate::loaders::ConversionError>> {
Ok([#(#to_bytes_implementations),*].concat())
}
}
Expand Down Expand Up @@ -87,14 +85,14 @@ fn derive_for_enum(
current_index += 1;
}

let from = add_from.then(|| quote! {
impl #impl_generics crate::loaders::FromBytes for #name #type_generics #where_clause {
fn from_bytes(byte_stream: &mut ByteStream, length_hint: Option<usize>) -> Result<Self, Box<crate::loaders::ConversionError>> {
crate::loaders::check_length_hint_none::<Self>(length_hint)?;

match crate::loaders::conversion_result::<Self, _>(#numeric_type::from_bytes(byte_stream, None))? as usize {
#( #indices => Ok(Self::#values), )*
invalid => Err(crate::loaders::ConversionError::from_message(format!("invalid enum variant {}", invalid))),
let from = add_from.then(|| {
quote! {
impl #impl_generics crate::loaders::FromBytes for #name #type_generics #where_clause {
fn from_bytes(byte_stream: &mut ByteStream) -> Result<Self, Box<crate::loaders::ConversionError>> {
match crate::loaders::conversion_result::<Self, _>(#numeric_type::from_bytes(byte_stream))? as usize {
#( #indices => Ok(Self::#values), )*
invalid => Err(crate::loaders::ConversionError::from_message(format!("invalid enum variant {}", invalid))),
}
}
}
}
Expand All @@ -105,11 +103,9 @@ fn derive_for_enum(
impl #impl_generics crate::loaders::ToBytes for #name #type_generics #where_clause {
// Temporary until serialization is always possible
#[allow(unreachable_code)]
fn to_bytes(&self, length_hint: Option<usize>) -> Result<Vec<u8>, Box<crate::loaders::ConversionError>> {
crate::loaders::check_length_hint_none::<Self>(length_hint)?;

fn to_bytes(&self) -> Result<Vec<u8>, Box<crate::loaders::ConversionError>> {
match self {
#( #name::#values => crate::loaders::conversion_result::<Self, _>((#indices as #numeric_type).to_bytes(None)), )*
#( #name::#values => crate::loaders::conversion_result::<Self, _>((#indices as #numeric_type).to_bytes()), )*
}
}
}
Expand Down
27 changes: 19 additions & 8 deletions procedural/src/byte/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,27 @@ pub fn byte_convertable_helper(data_struct: DataStruct) -> (Vec<TokenStream>, Ve
let field_type = field.ty;

let is_version = get_unique_attribute(&mut field.attrs, "version").is_some();

let is_packet_length = get_unique_attribute(&mut field.attrs, "packet_length").is_some();

let length_hint = get_unique_attribute(&mut field.attrs, "length_hint")
.map(|attribute| match attribute.meta {
syn::Meta::List(list) => list.tokens,
syn::Meta::Path(_) | syn::Meta::NameValue(_) => panic!("expected token stream in attribute"),
})
.map(|length_hint| quote!(((#length_hint) as usize).into()))
.unwrap_or(quote!(None));
.map(|length_hint| quote!((#length_hint) as usize));

let from_length_hint = match length_hint.clone() {
Some(length_hint) => {
let length_hint = remove_self_from_stream(length_hint.clone());
quote!(crate::loaders::FromBytesExt::from_n_bytes(byte_stream, #length_hint))
}
None => quote!(crate::loaders::FromBytes::from_bytes(byte_stream)),
};

let from_length_hint = remove_self_from_stream(length_hint.clone());
let to_length_hint = match length_hint {
Some(length_hint) => quote!(crate::loaders::ToBytesExt::to_n_bytes(&self.#field_identifier, #length_hint)),
None => quote!(crate::loaders::ToBytes::to_bytes(&self.#field_identifier)),
};

let repeating: Option<TokenStream> = get_unique_attribute(&mut field.attrs, "repeating").map(|attribute| match attribute.meta {
syn::Meta::List(list) => remove_self_from_stream(list.tokens),
Expand Down Expand Up @@ -95,13 +104,13 @@ pub fn byte_convertable_helper(data_struct: DataStruct) -> (Vec<TokenStream>, Ve
}

// base from bytes implementation
let from_implementation =
quote!(crate::loaders::conversion_result::<Self, _>(crate::loaders::FromBytes::from_bytes(byte_stream, #from_length_hint))?);
let from_implementation = quote!(crate::loaders::conversion_result::<Self, _>(#from_length_hint)?);

// wrap base implementation in a loop if the element can appear multiple times
let from_implementation = match repeating {
Some(repeat_count) => quote!({
let repeat_count = #repeat_count;
// TODO: Add check to make sure this allocation is not too big.
let mut vector = Vec::with_capacity(repeat_count as usize);

for _ in 0..repeat_count {
Expand All @@ -114,8 +123,10 @@ pub fn byte_convertable_helper(data_struct: DataStruct) -> (Vec<TokenStream>, Ve
let packet_length = packet_length
.as_ref()
.expect("repeating_remaining is used but no packet_length attribute is set");

quote!({
let repeat_count = (#packet_length - ((byte_stream.get_offset() - base_offset) as u16) - 2) / (<#field_type as crate::loaders::FixedByteSizeWrapper>::size_in_bytes(None) as u16);
// TODO: Add check to make sure this allocation is not too big.
let mut vector = Vec::with_capacity(repeat_count as usize);

for _ in 0..repeat_count {
Expand Down Expand Up @@ -145,11 +156,11 @@ pub fn byte_convertable_helper(data_struct: DataStruct) -> (Vec<TokenStream>, Ve
// base to byte implementation
let to_implementation = match is_repeating || version_restricted {
true => quote!({
panic!("implement for to_bytes aswell");
panic!("implement for to_bytes as well");
[0u8].as_slice()
}),
false => {
quote!(crate::loaders::conversion_result::<Self, _>(crate::loaders::ToBytes::to_bytes(&self.#field_identifier, #length_hint))?.as_slice())
quote!(crate::loaders::conversion_result::<Self, _>(#to_length_hint)?.as_slice())
}
};

Expand Down
12 changes: 5 additions & 7 deletions src/graphics/transform.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::ops::Add;
use cgmath::{Deg, Rad, Vector3};
use procedural::*;

use crate::loaders::{check_length_hint_none, conversion_result, ConversionError, FromBytes};
use crate::loaders::{conversion_result, ConversionError, FromBytes};

#[derive(Copy, Clone, Debug, Named, PrototypeElement)]
pub struct Transform {
Expand All @@ -14,12 +14,10 @@ pub struct Transform {
}

impl FromBytes for Transform {
fn from_bytes(byte_stream: &mut crate::loaders::ByteStream, length_hint: Option<usize>) -> Result<Self, Box<ConversionError>> {
check_length_hint_none::<Self>(length_hint)?;

let mut position = conversion_result::<Self, _>(<Vector3<f32>>::from_bytes(byte_stream, None))?;
let rotation = conversion_result::<Self, _>(<Vector3<f32>>::from_bytes(byte_stream, None))?;
let scale = conversion_result::<Self, _>(<Vector3<f32>>::from_bytes(byte_stream, None))?;
fn from_bytes(byte_stream: &mut crate::loaders::ByteStream) -> Result<Self, Box<ConversionError>> {
let mut position = conversion_result::<Self, _>(<Vector3<f32>>::from_bytes(byte_stream))?;
let rotation = conversion_result::<Self, _>(<Vector3<f32>>::from_bytes(byte_stream))?;
let scale = conversion_result::<Self, _>(<Vector3<f32>>::from_bytes(byte_stream))?;

// TODO: make this nicer
position.y = -position.y;
Expand Down
10 changes: 7 additions & 3 deletions src/loaders/action/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,11 @@ impl Actions {
let fs = &a.motions[frame as usize % a.motions.len()];

for sprite_clip in &fs.sprite_clips {
let texture = &sprite.textures[sprite_clip.sprite_number as usize];
// NOTE: `get` instead of a direct index in case a fallback was loaded
let Some(texture) = sprite.textures.get(sprite_clip.sprite_number as usize) else {
return;
};

let offset = sprite_clip.position.map(|component| component as f32);
let dimesions = sprite_clip
.size
Expand Down Expand Up @@ -256,11 +260,11 @@ impl ActionLoader {
let bytes = game_file_loader.get(&format!("data\\sprite\\{path}"))?;
let mut byte_stream = ByteStream::new(&bytes);

if <[u8; 2]>::from_bytes(&mut byte_stream, None).unwrap() != [b'A', b'C'] {
if <[u8; 2]>::from_bytes(&mut byte_stream).unwrap() != [b'A', b'C'] {
return Err(format!("failed to read magic number from {path}"));
}

let actions_data = match ActionsData::from_bytes(&mut byte_stream, None) {
let actions_data = match ActionsData::from_bytes(&mut byte_stream) {
Ok(actions_data) => actions_data,
Err(_error) => {
#[cfg(feature = "debug")]
Expand Down
6 changes: 3 additions & 3 deletions src/loaders/archive/native/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ impl Writable for NativeArchiveBuilder {
let mut bytes = Vec::new();

bytes.extend_from_slice(MAGIC_BYTES);
bytes.extend_from_slice(&file_header.to_bytes(None).unwrap());
bytes.extend_from_slice(&file_header.to_bytes().unwrap());
bytes.extend_from_slice(&self.data);

let mut file_table_data = Vec::new();

for file_information in self.file_table.values() {
file_table_data.extend_from_slice(&file_information.to_bytes(None).unwrap());
file_table_data.extend_from_slice(&file_information.to_bytes().unwrap());
}

let compressed_file_information_data = compress(&file_table_data, Format::Zlib, CompressionLevel::Default).unwrap();
let file_table = AssetTable::new(compressed_file_information_data.len() as u32, file_table_data.len() as u32);

bytes.extend_from_slice(&file_table.to_bytes(None).unwrap());
bytes.extend_from_slice(&file_table.to_bytes().unwrap());
bytes.extend_from_slice(&compressed_file_information_data);

std::fs::write(&self.os_file_path, bytes).expect("unable to write file");
Expand Down
6 changes: 3 additions & 3 deletions src/loaders/archive/native/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ impl Archive for NativeArchive {
// while being able to read without buffering the entire file.
let mut file_header_buffer = [0u8; UNPACKED_SIZE_OF_ARCHIVEHEADER];
file.read_exact(&mut file_header_buffer).unwrap();
let file_header = Header::from_bytes(&mut ByteStream::new(&file_header_buffer), None).unwrap();
let file_header = Header::from_bytes(&mut ByteStream::new(&file_header_buffer)).unwrap();
file_header.validate_version();

let _ = file.seek(SeekFrom::Current(file_header.get_file_table_offset() as i64)).unwrap();
let mut file_table_buffer = [0u8; UNPACKED_SIZE_OF_FILETABLE];

file.read_exact(&mut file_table_buffer).unwrap();
let file_table = AssetTable::from_bytes(&mut ByteStream::new(&file_table_buffer), None).unwrap();
let file_table = AssetTable::from_bytes(&mut ByteStream::new(&file_table_buffer)).unwrap();

let mut compressed_file_table_buffer = vec![0u8; file_table.get_compressed_size()];
file.read_exact(&mut compressed_file_table_buffer).unwrap();
Expand All @@ -68,7 +68,7 @@ impl Archive for NativeArchive {
let mut assets = HashMap::with_capacity(file_count);

for _index in 0..file_count {
let file_information = FileTableRow::from_bytes(&mut file_table_byte_stream, None).unwrap();
let file_information = FileTableRow::from_bytes(&mut file_table_byte_stream).unwrap();
let file_name = file_information.file_name.to_lowercase();

assets.insert(file_name, file_information);
Expand Down
22 changes: 4 additions & 18 deletions src/loaders/convertable/error.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ConversionErrorType {
UnusedLengthHint { type_name: &'static str, length_hint: usize },
MissingLengthHint { type_name: &'static str },
ByteStreamTooShort { type_name: &'static str },
DataTooBig { type_name: &'static str },
Specific { message: String },
}

Expand Down Expand Up @@ -40,17 +39,12 @@ impl std::fmt::Debug for ConversionError {
let stack = self.stack.join("::");

match &self.error_type {
ConversionErrorType::UnusedLengthHint { type_name, length_hint } => write!(
formatter,
"unused length hint ({}) while parsing {} in {}",
length_hint, type_name, stack
),
ConversionErrorType::MissingLengthHint { type_name } => {
write!(formatter, "missing length hint while parsing {} in {}", type_name, stack)
}
ConversionErrorType::ByteStreamTooShort { type_name } => {
write!(formatter, "byte stream too short while parsing {} in {}", type_name, stack)
}
ConversionErrorType::DataTooBig { type_name } => {
write!(formatter, "data is too big for the available space {} in {}", type_name, stack)
}
ConversionErrorType::Specific { message } => write!(formatter, "{} in {}", message, stack),
}
}
Expand Down Expand Up @@ -121,12 +115,4 @@ mod type_check {

assert!(error.is_byte_stream_too_short());
}

#[test]
fn other() {
let error_type = ConversionErrorType::MissingLengthHint { type_name: "test" };
let error = ConversionError::from_error_type(error_type.clone());

assert!(!error.is_byte_stream_too_short());
}
}
21 changes: 0 additions & 21 deletions src/loaders/convertable/helper.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,5 @@
use super::{ConversionError, ConversionErrorType, Named};

#[inline(always)]
pub fn check_length_hint_none<S: Named>(length_hint: Option<usize>) -> Result<(), Box<ConversionError>> {
match length_hint {
Some(length_hint) => Err(ConversionError::from_error_type(ConversionErrorType::UnusedLengthHint {
type_name: S::NAME,
length_hint,
})),
None => Ok(()),
}
}

#[inline(always)]
pub fn check_length_hint<S: Named>(length_hint: Option<usize>) -> Result<usize, Box<ConversionError>> {
match length_hint {
Some(length_hint) => Ok(length_hint),
None => Err(ConversionError::from_error_type(ConversionErrorType::MissingLengthHint {
type_name: S::NAME,
})),
}
}

#[inline(always)]
pub fn check_upper_bound<S: Named>(offset: usize, length: usize) -> Result<(), Box<ConversionError>> {
match offset < length {
Expand Down
Loading

0 comments on commit 8b05a9a

Please sign in to comment.