diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 1280028997..c519e27b6a 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -303,7 +303,7 @@ pub extern "C" fn set_focus_mode() { let entries: Vec = bytes .chunks(size_of::<::BytesType>()) - .map(|data| Uuid::from_bytes(data.try_into().unwrap())) + .map(|data| Uuid::try_from(data).unwrap()) .collect(); with_state_mut!(state, { @@ -523,7 +523,7 @@ pub extern "C" fn set_children() { let entries: Vec = bytes .chunks(size_of::<::BytesType>()) - .map(|data| Uuid::from_bytes(data.try_into().unwrap())) + .map(|data| Uuid::try_from(data).unwrap()) .collect(); set_children_set(entries); @@ -679,7 +679,7 @@ pub extern "C" fn propagate_modifiers(pixel_precision: bool) -> *mut u8 { let entries: Vec<_> = bytes .chunks(size_of::<::BytesType>()) - .map(|data| TransformEntry::from_bytes(data.try_into().unwrap())) + .map(|data| TransformEntry::try_from(data).unwrap()) .collect(); with_state!(state, { @@ -694,7 +694,7 @@ pub extern "C" fn set_modifiers() { let entries: Vec<_> = bytes .chunks(size_of::<::BytesType>()) - .map(|data| TransformEntry::from_bytes(data.try_into().unwrap())) + .map(|data| TransformEntry::try_from(data).unwrap()) .collect(); let mut modifiers = HashMap::new(); diff --git a/render-wasm/src/mem.rs b/render-wasm/src/mem.rs index bf5ce418b0..54cf4aa9d1 100644 --- a/render-wasm/src/mem.rs +++ b/render-wasm/src/mem.rs @@ -57,10 +57,8 @@ pub fn bytes_or_empty() -> Vec { guard.take().unwrap_or_default() } -pub trait SerializableResult { +pub trait SerializableResult: From + Into { type BytesType; - fn from_bytes(bytes: Self::BytesType) -> Self; - fn as_bytes(&self) -> Self::BytesType; fn clone_to_slice(&self, slice: &mut [u8]); } diff --git a/render-wasm/src/shapes/modifiers.rs b/render-wasm/src/shapes/modifiers.rs index 07c5230ce8..02e7911aaa 100644 --- a/render-wasm/src/shapes/modifiers.rs +++ b/render-wasm/src/shapes/modifiers.rs @@ -384,7 +384,7 @@ pub fn propagate_modifiers( if math::identitish(&entry.transform) { Modifier::Reflow(entry.id) } else { - Modifier::Transform(entry.clone()) + Modifier::Transform(*entry) } }) .collect(); diff --git a/render-wasm/src/shapes/text.rs b/render-wasm/src/shapes/text.rs index f99776d280..42cb6cd373 100644 --- a/render-wasm/src/shapes/text.rs +++ b/render-wasm/src/shapes/text.rs @@ -1053,7 +1053,7 @@ impl TextSpan { } #[allow(dead_code)] -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub struct PositionData { pub paragraph: u32, pub span: u32, diff --git a/render-wasm/src/shapes/transform.rs b/render-wasm/src/shapes/transform.rs index f3eba62d67..d6997599d8 100644 --- a/render-wasm/src/shapes/transform.rs +++ b/render-wasm/src/shapes/transform.rs @@ -23,13 +23,13 @@ impl Modifier { } } -#[derive(PartialEq, Debug, Clone)] +#[derive(PartialEq, Debug, Clone, Copy)] pub enum TransformEntrySource { Input, Propagate, } -#[derive(PartialEq, Debug, Clone)] +#[derive(PartialEq, Debug, Clone, Copy)] #[repr(C)] pub struct TransformEntry { pub id: Uuid, @@ -65,10 +65,8 @@ impl TransformEntry { } } -impl SerializableResult for TransformEntry { - type BytesType = [u8; 40]; - - fn from_bytes(bytes: Self::BytesType) -> Self { +impl From<[u8; 40]> for TransformEntry { + fn from(bytes: [u8; 40]) -> Self { let id = uuid_from_u32_quartet( u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]), u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]), @@ -89,29 +87,46 @@ impl SerializableResult for TransformEntry { ); TransformEntry::from_input(id, transform) } +} - fn as_bytes(&self) -> Self::BytesType { - let mut result: Self::BytesType = [0; 40]; - let (a, b, c, d) = uuid_to_u32_quartet(&self.id); +impl TryFrom<&[u8]> for TransformEntry { + type Error = String; + fn try_from(bytes: &[u8]) -> Result { + let bytes: [u8; 40] = bytes + .try_into() + .map_err(|_| "Invalid transform entry bytes".to_string())?; + Ok(TransformEntry::from(bytes)) + } +} + +impl From for [u8; 40] { + fn from(value: TransformEntry) -> Self { + let mut result = [0; 40]; + let (a, b, c, d) = uuid_to_u32_quartet(&value.id); result[0..4].clone_from_slice(&a.to_le_bytes()); result[4..8].clone_from_slice(&b.to_le_bytes()); result[8..12].clone_from_slice(&c.to_le_bytes()); result[12..16].clone_from_slice(&d.to_le_bytes()); - result[16..20].clone_from_slice(&self.transform[0].to_le_bytes()); - result[20..24].clone_from_slice(&self.transform[3].to_le_bytes()); - result[24..28].clone_from_slice(&self.transform[1].to_le_bytes()); - result[28..32].clone_from_slice(&self.transform[4].to_le_bytes()); - result[32..36].clone_from_slice(&self.transform[2].to_le_bytes()); - result[36..40].clone_from_slice(&self.transform[5].to_le_bytes()); + result[16..20].clone_from_slice(&value.transform[0].to_le_bytes()); + result[20..24].clone_from_slice(&value.transform[3].to_le_bytes()); + result[24..28].clone_from_slice(&value.transform[1].to_le_bytes()); + result[28..32].clone_from_slice(&value.transform[4].to_le_bytes()); + result[32..36].clone_from_slice(&value.transform[2].to_le_bytes()); + result[36..40].clone_from_slice(&value.transform[5].to_le_bytes()); result } +} + +impl SerializableResult for TransformEntry { + type BytesType = [u8; 40]; // The generic trait doesn't know the size of the array. This is why the // clone needs to be here even if it could be generic. fn clone_to_slice(&self, slice: &mut [u8]) { - slice.clone_from_slice(&self.as_bytes()); + let bytes = Self::BytesType::from(*self); + slice.clone_from_slice(&bytes); } } @@ -198,8 +213,8 @@ mod tests { Matrix::new_all(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 0.0, 0.0, 1.0), ); - let bytes = entry.as_bytes(); + let bytes: [u8; 40] = entry.into(); - assert_eq!(entry, TransformEntry::from_bytes(bytes)); + assert_eq!(entry, TransformEntry::from(bytes)); } } diff --git a/render-wasm/src/uuid.rs b/render-wasm/src/uuid.rs index 519d2e158a..e4f5120b59 100644 --- a/render-wasm/src/uuid.rs +++ b/render-wasm/src/uuid.rs @@ -49,10 +49,8 @@ impl fmt::Display for Uuid { } } -impl SerializableResult for Uuid { - type BytesType = [u8; 16]; - - fn from_bytes(bytes: Self::BytesType) -> Self { +impl From<[u8; 16]> for Uuid { + fn from(bytes: [u8; 16]) -> Self { Self(*uuid_from_u32_quartet( u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]), u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]), @@ -60,10 +58,22 @@ impl SerializableResult for Uuid { u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]), )) } +} - fn as_bytes(&self) -> Self::BytesType { - let mut result: Self::BytesType = [0; 16]; - let (a, b, c, d) = uuid_to_u32_quartet(self); +impl TryFrom<&[u8]> for Uuid { + type Error = String; + fn try_from(bytes: &[u8]) -> Result { + let bytes: [u8; 16] = bytes + .try_into() + .map_err(|_| "Invalid UUID bytes".to_string())?; + Ok(Self::from(bytes)) + } +} + +impl From for [u8; 16] { + fn from(value: Uuid) -> Self { + let mut result = [0; 16]; + let (a, b, c, d) = uuid_to_u32_quartet(&value); result[0..4].clone_from_slice(&a.to_le_bytes()); result[4..8].clone_from_slice(&b.to_le_bytes()); result[8..12].clone_from_slice(&c.to_le_bytes()); @@ -71,10 +81,15 @@ impl SerializableResult for Uuid { result } +} + +impl SerializableResult for Uuid { + type BytesType = [u8; 16]; // The generic trait doesn't know the size of the array. This is why the // clone needs to be here even if it could be generic. fn clone_to_slice(&self, slice: &mut [u8]) { - slice.clone_from_slice(&self.as_bytes()); + let bytes = Self::BytesType::from(*self); + slice.clone_from_slice(&bytes); } } diff --git a/render-wasm/src/wasm/fills/image.rs b/render-wasm/src/wasm/fills/image.rs index 4c1e49b94d..9c7a5d312b 100644 --- a/render-wasm/src/wasm/fills/image.rs +++ b/render-wasm/src/wasm/fills/image.rs @@ -1,5 +1,5 @@ use crate::mem; -use crate::mem::SerializableResult; +// use crate::mem::SerializableResult; use crate::uuid::Uuid; use crate::with_state_mut; use crate::STATE; @@ -48,8 +48,8 @@ pub struct ShapeImageIds { impl From<[u8; IMAGE_IDS_SIZE]> for ShapeImageIds { fn from(bytes: [u8; IMAGE_IDS_SIZE]) -> Self { - let shape_id = Uuid::from_bytes(bytes[0..16].try_into().unwrap()); - let image_id = Uuid::from_bytes(bytes[16..32].try_into().unwrap()); + let shape_id = Uuid::try_from(&bytes[0..16]).unwrap(); + let image_id = Uuid::try_from(&bytes[16..32]).unwrap(); ShapeImageIds { shape_id, image_id } } } @@ -93,7 +93,7 @@ pub extern "C" fn store_image() { /// Stores an image from an existing WebGL texture, avoiding re-decoding /// Expected memory layout: /// - bytes 0-15: shape UUID -/// - bytes 16-31: image UUID +/// - bytes 16-31: image UUID /// - bytes 32-35: is_thumbnail flag (u32) /// - bytes 36-39: GL texture ID (u32) /// - bytes 40-43: width (i32) diff --git a/render-wasm/src/wasm/paths.rs b/render-wasm/src/wasm/paths.rs index 744ee361f6..815c9d2804 100644 --- a/render-wasm/src/wasm/paths.rs +++ b/render-wasm/src/wasm/paths.rs @@ -51,25 +51,20 @@ impl TryFrom<&[u8]> for RawSegmentData { } } +impl From for [u8; RAW_SEGMENT_DATA_SIZE] { + fn from(value: RawSegmentData) -> Self { + unsafe { std::mem::transmute(value) } + } +} + impl SerializableResult for RawSegmentData { type BytesType = [u8; RAW_SEGMENT_DATA_SIZE]; - fn from_bytes(bytes: Self::BytesType) -> Self { - unsafe { std::mem::transmute(bytes) } - } - - fn as_bytes(&self) -> Self::BytesType { - let ptr = self as *const RawSegmentData as *const u8; - let bytes: &[u8] = unsafe { std::slice::from_raw_parts(ptr, RAW_SEGMENT_DATA_SIZE) }; - let mut result = [0; RAW_SEGMENT_DATA_SIZE]; - result.copy_from_slice(bytes); - result - } - // The generic trait doesn't know the size of the array. This is why the // clone needs to be here even if it could be generic. fn clone_to_slice(&self, slice: &mut [u8]) { - slice.clone_from_slice(&self.as_bytes()); + let bytes = Self::BytesType::from(*self); + slice.clone_from_slice(&bytes); } } diff --git a/render-wasm/src/wasm/paths/bools.rs b/render-wasm/src/wasm/paths/bools.rs index e3c7b15c59..36bd0e4440 100644 --- a/render-wasm/src/wasm/paths/bools.rs +++ b/render-wasm/src/wasm/paths/bools.rs @@ -48,7 +48,7 @@ pub extern "C" fn calculate_bool(raw_bool_type: u8) -> *mut u8 { let entries: Vec = bytes .chunks(size_of::<::BytesType>()) - .map(|data| Uuid::from_bytes(data.try_into().unwrap())) + .map(|data| Uuid::try_from(data).unwrap()) .collect(); mem::free_bytes(); diff --git a/render-wasm/src/wasm/text.rs b/render-wasm/src/wasm/text.rs index a8303756f5..df2e72f841 100644 --- a/render-wasm/src/wasm/text.rs +++ b/render-wasm/src/wasm/text.rs @@ -415,24 +415,26 @@ pub extern "C" fn get_caret_position_at(x: f32, y: f32) -> i32 { const RAW_POSITION_DATA_SIZE: usize = size_of::(); -impl SerializableResult for shapes::PositionData { - type BytesType = [u8; RAW_POSITION_DATA_SIZE]; - - fn from_bytes(bytes: Self::BytesType) -> Self { +impl From<[u8; RAW_POSITION_DATA_SIZE]> for shapes::PositionData { + fn from(bytes: [u8; RAW_POSITION_DATA_SIZE]) -> Self { unsafe { std::mem::transmute(bytes) } } - fn as_bytes(&self) -> Self::BytesType { - let ptr = self as *const shapes::PositionData as *const u8; - let bytes: &[u8] = unsafe { std::slice::from_raw_parts(ptr, RAW_POSITION_DATA_SIZE) }; - let mut result = [0; RAW_POSITION_DATA_SIZE]; - result.copy_from_slice(bytes); - result +} + +impl From for [u8; RAW_POSITION_DATA_SIZE] { + fn from(value: shapes::PositionData) -> Self { + unsafe { std::mem::transmute(value) } } +} + +impl SerializableResult for shapes::PositionData { + type BytesType = [u8; RAW_POSITION_DATA_SIZE]; // The generic trait doesn't know the size of the array. This is why the // clone needs to be here even if it could be generic. fn clone_to_slice(&self, slice: &mut [u8]) { - slice.clone_from_slice(&self.as_bytes()); + let bytes = Self::BytesType::from(*self); + slice.clone_from_slice(&bytes); } }