bytes: FromBytes trait and round trip tests

This commit is contained in:
Carter Anderson 2020-06-21 12:25:36 -07:00
parent ecea30cadb
commit 17d70f7d67
2 changed files with 128 additions and 2 deletions

View File

@ -21,6 +21,7 @@ where
let bytes = self.as_bytes(); let bytes = self.as_bytes();
buffer[0..self.byte_len()].copy_from_slice(bytes) buffer[0..self.byte_len()].copy_from_slice(bytes)
} }
fn byte_len(&self) -> usize { fn byte_len(&self) -> usize {
std::mem::size_of::<Self>() std::mem::size_of::<Self>()
} }
@ -30,6 +31,23 @@ pub trait AsBytes {
fn as_bytes(&self) -> &[u8]; fn as_bytes(&self) -> &[u8];
} }
pub trait FromBytes {
fn from_bytes(bytes: &[u8]) -> Self;
}
impl<T> FromBytes for T
where
T: Byteable + Clone,
{
fn from_bytes(bytes: &[u8]) -> Self {
unsafe {
let byte_ptr = bytes.as_ptr();
let ptr = byte_ptr as *const Self;
(*ptr).clone()
}
}
}
impl<T> AsBytes for T impl<T> AsBytes for T
where where
T: Byteable, T: Byteable,
@ -84,6 +102,13 @@ impl Bytes for Vec2 {
} }
} }
impl FromBytes for Vec2 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 2]>::from_bytes(bytes);
Vec2::from(array)
}
}
impl Bytes for Vec3 { impl Bytes for Vec3 {
fn write_bytes(&self, buffer: &mut [u8]) { fn write_bytes(&self, buffer: &mut [u8]) {
let array: [f32; 3] = (*self).into(); let array: [f32; 3] = (*self).into();
@ -95,6 +120,13 @@ impl Bytes for Vec3 {
} }
} }
impl FromBytes for Vec3 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 3]>::from_bytes(bytes);
Vec3::from(array)
}
}
impl Bytes for Vec4 { impl Bytes for Vec4 {
fn write_bytes(&self, buffer: &mut [u8]) { fn write_bytes(&self, buffer: &mut [u8]) {
let array: [f32; 4] = (*self).into(); let array: [f32; 4] = (*self).into();
@ -105,6 +137,13 @@ impl Bytes for Vec4 {
} }
} }
impl FromBytes for Vec4 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 4]>::from_bytes(bytes);
Vec4::from(array)
}
}
impl Bytes for Mat4 { impl Bytes for Mat4 {
fn write_bytes(&self, buffer: &mut [u8]) { fn write_bytes(&self, buffer: &mut [u8]) {
let array = self.to_cols_array(); let array = self.to_cols_array();
@ -115,6 +154,13 @@ impl Bytes for Mat4 {
} }
} }
impl FromBytes for Mat4 {
fn from_bytes(bytes: &[u8]) -> Self {
let array = <[f32; 16]>::from_bytes(bytes);
Mat4::from_cols_array(&array)
}
}
impl<T> Bytes for Option<T> impl<T> Bytes for Option<T>
where where
T: Bytes, T: Bytes,
@ -129,6 +175,19 @@ where
} }
} }
impl<T> FromBytes for Option<T>
where
T: FromBytes,
{
fn from_bytes(bytes: &[u8]) -> Self {
if bytes.len() == 0 {
None
} else {
Some(T::from_bytes(bytes))
}
}
}
impl<T> Bytes for Vec<T> impl<T> Bytes for Vec<T>
where where
T: Sized + Byteable, T: Sized + Byteable,
@ -141,3 +200,72 @@ where
self.as_slice().as_bytes().len() self.as_slice().as_bytes().len()
} }
} }
impl<T> FromBytes for Vec<T>
where
T: Sized + Clone + Byteable,
{
fn from_bytes(bytes: &[u8]) -> Self {
unsafe {
let byte_ptr = bytes.as_ptr() as *const T;
let len = bytes.len() / std::mem::size_of::<T>();
let slice = core::slice::from_raw_parts::<T>(byte_ptr, len);
slice.to_vec()
}
}
}
#[cfg(test)]
mod tests {
use super::{FromBytes, Bytes};
use glam::{Vec3, Vec2, Vec4, Mat4};
fn test_round_trip<T: Bytes + FromBytes + std::fmt::Debug + PartialEq>(value: T) {
let mut bytes = vec![0; value.byte_len()];
value.write_bytes(&mut bytes);
let result = T::from_bytes(&bytes);
assert_eq!(value, result);
}
#[test]
fn test_u32_bytes_round_trip() {
test_round_trip(123u32);
}
#[test]
fn test_f64_bytes_round_trip() {
test_round_trip(123f64);
}
#[test]
fn test_vec_bytes_round_trip() {
test_round_trip(vec![1u32, 2u32, 3u32]);
}
#[test]
fn test_option_bytes_round_trip() {
test_round_trip(Some(123u32));
test_round_trip(Option::<u32>::None);
}
#[test]
fn test_vec2_round_trip() {
test_round_trip(Vec2::new(1.0, 2.0));
}
#[test]
fn test_vec3_round_trip() {
test_round_trip(Vec3::new(1.0, 2.0, 3.0));
}
#[test]
fn test_vec4_round_trip() {
test_round_trip(Vec4::new(1.0, 2.0, 3.0, 4.0));
}
#[test]
fn test_mat4_round_trip() {
test_round_trip(Mat4::identity());
}
}

View File

@ -9,7 +9,6 @@ pub fn derive_render_resource(input: TokenStream) -> TokenStream {
let bevy_render_path: Path = get_path(&modules.bevy_render); let bevy_render_path: Path = get_path(&modules.bevy_render);
let bevy_asset_path: Path = get_path(&modules.bevy_asset); let bevy_asset_path: Path = get_path(&modules.bevy_asset);
let bevy_core_path: Path = get_path(&modules.bevy_core);
let struct_name = &ast.ident; let struct_name = &ast.ident;
TokenStream::from(quote! { TokenStream::from(quote! {
@ -18,7 +17,6 @@ pub fn derive_render_resource(input: TokenStream) -> TokenStream {
Some(#bevy_render_path::render_resource::RenderResourceType::Buffer) Some(#bevy_render_path::render_resource::RenderResourceType::Buffer)
} }
fn write_buffer_bytes(&self, buffer: &mut [u8]) { fn write_buffer_bytes(&self, buffer: &mut [u8]) {
use #bevy_core_path::bytes::Bytes;
self.write_bytes(buffer); self.write_bytes(buffer);
} }
fn buffer_byte_len(&self) -> Option<usize> { fn buffer_byte_len(&self) -> Option<usize> {