♻️ Make SerializableResult to depend on From traits

This commit is contained in:
Belén Albeza
2025-12-11 15:17:33 +01:00
parent ea4d0e1238
commit 0a7a65af5d
10 changed files with 89 additions and 64 deletions

View File

@@ -303,7 +303,7 @@ pub extern "C" fn set_focus_mode() {
let entries: Vec<Uuid> = bytes let entries: Vec<Uuid> = bytes
.chunks(size_of::<<Uuid as SerializableResult>::BytesType>()) .chunks(size_of::<<Uuid as SerializableResult>::BytesType>())
.map(|data| Uuid::from_bytes(data.try_into().unwrap())) .map(|data| Uuid::try_from(data).unwrap())
.collect(); .collect();
with_state_mut!(state, { with_state_mut!(state, {
@@ -523,7 +523,7 @@ pub extern "C" fn set_children() {
let entries: Vec<Uuid> = bytes let entries: Vec<Uuid> = bytes
.chunks(size_of::<<Uuid as SerializableResult>::BytesType>()) .chunks(size_of::<<Uuid as SerializableResult>::BytesType>())
.map(|data| Uuid::from_bytes(data.try_into().unwrap())) .map(|data| Uuid::try_from(data).unwrap())
.collect(); .collect();
set_children_set(entries); set_children_set(entries);
@@ -679,7 +679,7 @@ pub extern "C" fn propagate_modifiers(pixel_precision: bool) -> *mut u8 {
let entries: Vec<_> = bytes let entries: Vec<_> = bytes
.chunks(size_of::<<TransformEntry as SerializableResult>::BytesType>()) .chunks(size_of::<<TransformEntry as SerializableResult>::BytesType>())
.map(|data| TransformEntry::from_bytes(data.try_into().unwrap())) .map(|data| TransformEntry::try_from(data).unwrap())
.collect(); .collect();
with_state!(state, { with_state!(state, {
@@ -694,7 +694,7 @@ pub extern "C" fn set_modifiers() {
let entries: Vec<_> = bytes let entries: Vec<_> = bytes
.chunks(size_of::<<TransformEntry as SerializableResult>::BytesType>()) .chunks(size_of::<<TransformEntry as SerializableResult>::BytesType>())
.map(|data| TransformEntry::from_bytes(data.try_into().unwrap())) .map(|data| TransformEntry::try_from(data).unwrap())
.collect(); .collect();
let mut modifiers = HashMap::new(); let mut modifiers = HashMap::new();

View File

@@ -57,10 +57,8 @@ pub fn bytes_or_empty() -> Vec<u8> {
guard.take().unwrap_or_default() guard.take().unwrap_or_default()
} }
pub trait SerializableResult { pub trait SerializableResult: From<Self::BytesType> + Into<Self::BytesType> {
type BytesType; type BytesType;
fn from_bytes(bytes: Self::BytesType) -> Self;
fn as_bytes(&self) -> Self::BytesType;
fn clone_to_slice(&self, slice: &mut [u8]); fn clone_to_slice(&self, slice: &mut [u8]);
} }

View File

@@ -384,7 +384,7 @@ pub fn propagate_modifiers(
if math::identitish(&entry.transform) { if math::identitish(&entry.transform) {
Modifier::Reflow(entry.id) Modifier::Reflow(entry.id)
} else { } else {
Modifier::Transform(entry.clone()) Modifier::Transform(*entry)
} }
}) })
.collect(); .collect();

View File

@@ -1053,7 +1053,7 @@ impl TextSpan {
} }
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub struct PositionData { pub struct PositionData {
pub paragraph: u32, pub paragraph: u32,
pub span: u32, pub span: u32,

View File

@@ -23,13 +23,13 @@ impl Modifier {
} }
} }
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone, Copy)]
pub enum TransformEntrySource { pub enum TransformEntrySource {
Input, Input,
Propagate, Propagate,
} }
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone, Copy)]
#[repr(C)] #[repr(C)]
pub struct TransformEntry { pub struct TransformEntry {
pub id: Uuid, pub id: Uuid,
@@ -65,10 +65,8 @@ impl TransformEntry {
} }
} }
impl SerializableResult for TransformEntry { impl From<[u8; 40]> for TransformEntry {
type BytesType = [u8; 40]; fn from(bytes: [u8; 40]) -> Self {
fn from_bytes(bytes: Self::BytesType) -> Self {
let id = uuid_from_u32_quartet( let id = uuid_from_u32_quartet(
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]), u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]), 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) TransformEntry::from_input(id, transform)
} }
}
fn as_bytes(&self) -> Self::BytesType { impl TryFrom<&[u8]> for TransformEntry {
let mut result: Self::BytesType = [0; 40]; type Error = String;
let (a, b, c, d) = uuid_to_u32_quartet(&self.id); fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes: [u8; 40] = bytes
.try_into()
.map_err(|_| "Invalid transform entry bytes".to_string())?;
Ok(TransformEntry::from(bytes))
}
}
impl From<TransformEntry> 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[0..4].clone_from_slice(&a.to_le_bytes());
result[4..8].clone_from_slice(&b.to_le_bytes()); result[4..8].clone_from_slice(&b.to_le_bytes());
result[8..12].clone_from_slice(&c.to_le_bytes()); result[8..12].clone_from_slice(&c.to_le_bytes());
result[12..16].clone_from_slice(&d.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[16..20].clone_from_slice(&value.transform[0].to_le_bytes());
result[20..24].clone_from_slice(&self.transform[3].to_le_bytes()); result[20..24].clone_from_slice(&value.transform[3].to_le_bytes());
result[24..28].clone_from_slice(&self.transform[1].to_le_bytes()); result[24..28].clone_from_slice(&value.transform[1].to_le_bytes());
result[28..32].clone_from_slice(&self.transform[4].to_le_bytes()); result[28..32].clone_from_slice(&value.transform[4].to_le_bytes());
result[32..36].clone_from_slice(&self.transform[2].to_le_bytes()); result[32..36].clone_from_slice(&value.transform[2].to_le_bytes());
result[36..40].clone_from_slice(&self.transform[5].to_le_bytes()); result[36..40].clone_from_slice(&value.transform[5].to_le_bytes());
result result
} }
}
impl SerializableResult for TransformEntry {
type BytesType = [u8; 40];
// The generic trait doesn't know the size of the array. This is why the // 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. // clone needs to be here even if it could be generic.
fn clone_to_slice(&self, slice: &mut [u8]) { 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), 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));
} }
} }

View File

@@ -49,10 +49,8 @@ impl fmt::Display for Uuid {
} }
} }
impl SerializableResult for Uuid { impl From<[u8; 16]> for Uuid {
type BytesType = [u8; 16]; fn from(bytes: [u8; 16]) -> Self {
fn from_bytes(bytes: Self::BytesType) -> Self {
Self(*uuid_from_u32_quartet( Self(*uuid_from_u32_quartet(
u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]), u32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
u32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]), 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]]), u32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
)) ))
} }
}
fn as_bytes(&self) -> Self::BytesType { impl TryFrom<&[u8]> for Uuid {
let mut result: Self::BytesType = [0; 16]; type Error = String;
let (a, b, c, d) = uuid_to_u32_quartet(self); fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
let bytes: [u8; 16] = bytes
.try_into()
.map_err(|_| "Invalid UUID bytes".to_string())?;
Ok(Self::from(bytes))
}
}
impl From<Uuid> 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[0..4].clone_from_slice(&a.to_le_bytes());
result[4..8].clone_from_slice(&b.to_le_bytes()); result[4..8].clone_from_slice(&b.to_le_bytes());
result[8..12].clone_from_slice(&c.to_le_bytes()); result[8..12].clone_from_slice(&c.to_le_bytes());
@@ -71,10 +81,15 @@ impl SerializableResult for Uuid {
result result
} }
}
impl SerializableResult for Uuid {
type BytesType = [u8; 16];
// The generic trait doesn't know the size of the array. This is why the // 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. // clone needs to be here even if it could be generic.
fn clone_to_slice(&self, slice: &mut [u8]) { 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);
} }
} }

View File

@@ -1,5 +1,5 @@
use crate::mem; use crate::mem;
use crate::mem::SerializableResult; // use crate::mem::SerializableResult;
use crate::uuid::Uuid; use crate::uuid::Uuid;
use crate::with_state_mut; use crate::with_state_mut;
use crate::STATE; use crate::STATE;
@@ -48,8 +48,8 @@ pub struct ShapeImageIds {
impl From<[u8; IMAGE_IDS_SIZE]> for ShapeImageIds { impl From<[u8; IMAGE_IDS_SIZE]> for ShapeImageIds {
fn from(bytes: [u8; IMAGE_IDS_SIZE]) -> Self { fn from(bytes: [u8; IMAGE_IDS_SIZE]) -> Self {
let shape_id = Uuid::from_bytes(bytes[0..16].try_into().unwrap()); let shape_id = Uuid::try_from(&bytes[0..16]).unwrap();
let image_id = Uuid::from_bytes(bytes[16..32].try_into().unwrap()); let image_id = Uuid::try_from(&bytes[16..32]).unwrap();
ShapeImageIds { shape_id, image_id } 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 /// Stores an image from an existing WebGL texture, avoiding re-decoding
/// Expected memory layout: /// Expected memory layout:
/// - bytes 0-15: shape UUID /// - bytes 0-15: shape UUID
/// - bytes 16-31: image UUID /// - bytes 16-31: image UUID
/// - bytes 32-35: is_thumbnail flag (u32) /// - bytes 32-35: is_thumbnail flag (u32)
/// - bytes 36-39: GL texture ID (u32) /// - bytes 36-39: GL texture ID (u32)
/// - bytes 40-43: width (i32) /// - bytes 40-43: width (i32)

View File

@@ -51,25 +51,20 @@ impl TryFrom<&[u8]> for RawSegmentData {
} }
} }
impl From<RawSegmentData> for [u8; RAW_SEGMENT_DATA_SIZE] {
fn from(value: RawSegmentData) -> Self {
unsafe { std::mem::transmute(value) }
}
}
impl SerializableResult for RawSegmentData { impl SerializableResult for RawSegmentData {
type BytesType = [u8; RAW_SEGMENT_DATA_SIZE]; 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 // 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. // clone needs to be here even if it could be generic.
fn clone_to_slice(&self, slice: &mut [u8]) { 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);
} }
} }

View File

@@ -48,7 +48,7 @@ pub extern "C" fn calculate_bool(raw_bool_type: u8) -> *mut u8 {
let entries: Vec<Uuid> = bytes let entries: Vec<Uuid> = bytes
.chunks(size_of::<<Uuid as SerializableResult>::BytesType>()) .chunks(size_of::<<Uuid as SerializableResult>::BytesType>())
.map(|data| Uuid::from_bytes(data.try_into().unwrap())) .map(|data| Uuid::try_from(data).unwrap())
.collect(); .collect();
mem::free_bytes(); mem::free_bytes();

View File

@@ -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::<shapes::PositionData>(); const RAW_POSITION_DATA_SIZE: usize = size_of::<shapes::PositionData>();
impl SerializableResult for shapes::PositionData { impl From<[u8; RAW_POSITION_DATA_SIZE]> for shapes::PositionData {
type BytesType = [u8; RAW_POSITION_DATA_SIZE]; fn from(bytes: [u8; RAW_POSITION_DATA_SIZE]) -> Self {
fn from_bytes(bytes: Self::BytesType) -> Self {
unsafe { std::mem::transmute(bytes) } 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) }; impl From<shapes::PositionData> for [u8; RAW_POSITION_DATA_SIZE] {
let mut result = [0; RAW_POSITION_DATA_SIZE]; fn from(value: shapes::PositionData) -> Self {
result.copy_from_slice(bytes); unsafe { std::mem::transmute(value) }
result
} }
}
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 // 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. // clone needs to be here even if it could be generic.
fn clone_to_slice(&self, slice: &mut [u8]) { 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);
} }
} }