* implement const cbor encoding + decoding for basic types * implement map encoding and decoding * fix map test * all tests passing * dynamically sized arrays * smaller str encoding * swap array and list and add more documentation * move serialization and deserialization for each struct together * support both legacy and new assets * bump const serialize version * fix asset conversion code * pull out manganis symbol struct from tuble * test reading old asset versions * more list/array cleanup and bump rust version * fix clippy * switch cli opt port * install playwright deps * split cli-optimization package to avoid two dioxus' in the same crate * fix clippy * force the toast.png asset to be included in the linker stage #[used] has platform depedant behavior * bundle both formats in the link section and only use the asset the cli changed * remove sudo which doesn't exist on windows * add binstall to the playwright workflow * separate bin target for the old cli * lockfile * cargo update to get versions shaken out * notes on binstalls, add back `.read()` for compat * use 0.8.0-alpha.0 for const-serialize instead of 0.8 this ensures we can still publish breaking changes on 0.8 without taking over the full version * fix clippy in example * small debug nits * update rust-overlay in nix * fix flake? * migrate to new structure * just comment out binstalls * just remove old test harness --------- Co-authored-by: Jonathan Kelley <jkelleyrtp@gmail.com>
120 lines
3.8 KiB
Rust
120 lines
3.8 KiB
Rust
use crate::*;
|
|
|
|
/// The layout for a dynamically sized list. The list layout is just a length and an item layout.
|
|
#[derive(Debug, Copy, Clone)]
|
|
pub struct ListLayout {
|
|
/// The size of the struct backing the list
|
|
pub(crate) size: usize,
|
|
/// The byte offset of the length field
|
|
len_offset: usize,
|
|
/// The layout of the length field
|
|
len_layout: PrimitiveLayout,
|
|
/// The byte offset of the data field
|
|
data_offset: usize,
|
|
/// The layout of the data field
|
|
data_layout: ArrayLayout,
|
|
}
|
|
|
|
impl ListLayout {
|
|
/// Create a new list layout
|
|
pub const fn new(
|
|
size: usize,
|
|
len_offset: usize,
|
|
len_layout: PrimitiveLayout,
|
|
data_offset: usize,
|
|
data_layout: ArrayLayout,
|
|
) -> Self {
|
|
Self {
|
|
size,
|
|
len_offset,
|
|
len_layout,
|
|
data_offset,
|
|
data_layout,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Serialize a dynamically sized list that is stored at the pointer passed in
|
|
pub(crate) const unsafe fn serialize_const_list(
|
|
ptr: *const (),
|
|
mut to: ConstVec<u8>,
|
|
layout: &ListLayout,
|
|
) -> ConstVec<u8> {
|
|
// Read the length of the list
|
|
let len_ptr = ptr.wrapping_byte_offset(layout.len_offset as _);
|
|
let len = layout.len_layout.read(len_ptr as *const u8) as usize;
|
|
|
|
let data_ptr = ptr.wrapping_byte_offset(layout.data_offset as _);
|
|
let item_layout = layout.data_layout.item_layout;
|
|
// If the item size is 1, deserialize as bytes directly
|
|
if item_layout.size() == 1 {
|
|
let slice = std::slice::from_raw_parts(data_ptr as *const u8, len);
|
|
to = write_bytes(to, slice);
|
|
}
|
|
// Otherwise, deserialize as a list of items
|
|
else {
|
|
let mut i = 0;
|
|
to = write_array(to, len);
|
|
while i < len {
|
|
let item = data_ptr.wrapping_byte_offset((i * item_layout.size()) as _);
|
|
to = serialize_const_ptr(item, to, item_layout);
|
|
i += 1;
|
|
}
|
|
}
|
|
to
|
|
}
|
|
|
|
/// Deserialize a list type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
|
|
pub(crate) const fn deserialize_const_list<'a>(
|
|
from: &'a [u8],
|
|
layout: &ListLayout,
|
|
out: &mut [MaybeUninit<u8>],
|
|
) -> Option<&'a [u8]> {
|
|
let Some((_, len_out)) = out.split_at_mut_checked(layout.len_offset) else {
|
|
return None;
|
|
};
|
|
|
|
// If the list items are only one byte, serialize as bytes directly
|
|
let item_layout = layout.data_layout.item_layout;
|
|
if item_layout.size() == 1 {
|
|
let Ok((bytes, new_from)) = take_bytes(from) else {
|
|
return None;
|
|
};
|
|
// Write out the length of the list
|
|
layout.len_layout.write(bytes.len() as u32, len_out);
|
|
let Some((_, data_out)) = out.split_at_mut_checked(layout.data_offset) else {
|
|
return None;
|
|
};
|
|
let mut offset = 0;
|
|
while offset < bytes.len() {
|
|
data_out[offset] = MaybeUninit::new(bytes[offset]);
|
|
offset += 1;
|
|
}
|
|
Some(new_from)
|
|
}
|
|
// Otherwise, serialize as an list of objects
|
|
else {
|
|
let Ok((len, mut from)) = take_array(from) else {
|
|
return None;
|
|
};
|
|
// Write out the length of the list
|
|
layout.len_layout.write(len as u32, len_out);
|
|
let Some((_, mut data_out)) = out.split_at_mut_checked(layout.data_offset) else {
|
|
return None;
|
|
};
|
|
let mut i = 0;
|
|
while i < len {
|
|
let Some(new_from) = deserialize_const_ptr(from, item_layout, data_out) else {
|
|
return None;
|
|
};
|
|
let Some((_, item_out)) = data_out.split_at_mut_checked(item_layout.size()) else {
|
|
return None;
|
|
};
|
|
data_out = item_out;
|
|
from = new_from;
|
|
i += 1;
|
|
}
|
|
Some(from)
|
|
}
|
|
}
|