Files
Evan AlmloffandJonathan Kelley c977cc125e Switch const serialize to use CBOR (#4932)
* 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>
2025-12-28 21:49:34 -05:00

343 lines
8.8 KiB
Rust

use const_serialize::{deserialize_const, serialize_const, ConstVec, SerializeConst};
use std::mem::MaybeUninit;
#[test]
fn test_transmute_bytes_to_enum() {
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C, u8)]
enum Enum<T> {
A { one: u32, two: u16 },
B { one: u8, two: T } = 15,
}
#[repr(C)]
#[derive(Debug, PartialEq)]
struct A {
one: u32,
two: u16,
}
#[repr(C)]
#[derive(Debug, PartialEq)]
struct B<T> {
one: u8,
two: T,
}
const SIZE: usize = std::mem::size_of::<Enum<u16>>();
let mut out = [MaybeUninit::uninit(); SIZE];
let discriminate_size = std::mem::size_of::<u8>();
let tag_align = 0;
let union_alignment = std::mem::align_of::<A>().max(std::mem::align_of::<B<u16>>());
let data_align = (discriminate_size / union_alignment) + union_alignment;
let a_one_align = std::mem::offset_of!(A, one);
let a_two_align = std::mem::offset_of!(A, two);
let b_one_align = std::mem::offset_of!(B<u16>, one);
let b_two_align = std::mem::offset_of!(B<u16>, two);
let one = 1234u32;
let two = 5678u16;
let first = Enum::A { one, two };
for (i, byte) in one.to_le_bytes().iter().enumerate() {
out[data_align + i + a_one_align] = MaybeUninit::new(*byte);
}
for (i, byte) in two.to_le_bytes().iter().enumerate() {
out[data_align + i + a_two_align] = MaybeUninit::new(*byte);
}
out[tag_align] = MaybeUninit::new(0);
let out = unsafe { std::mem::transmute_copy::<[MaybeUninit<u8>; SIZE], Enum<u16>>(&out) };
assert_eq!(out, first);
let mut out = [MaybeUninit::uninit(); SIZE];
let one = 123u8;
let two = 58u16;
let second = Enum::B { one, two };
for (i, byte) in one.to_le_bytes().iter().enumerate() {
out[data_align + i + b_one_align] = MaybeUninit::new(*byte);
}
for (i, byte) in two.to_le_bytes().iter().enumerate() {
out[data_align + i + b_two_align] = MaybeUninit::new(*byte);
}
out[tag_align] = MaybeUninit::new(15);
let out = unsafe { std::mem::transmute_copy::<[MaybeUninit<u8>; SIZE], Enum<u16>>(&out) };
assert_eq!(out, second);
}
#[test]
fn test_serialize_enum() {
#[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum Enum {
A { one: u32, two: u16 },
B { one: u8, two: u16 } = 15,
}
println!("{:#?}", Enum::MEMORY_LAYOUT);
let data = Enum::A {
one: 0x11111111,
two: 0x22,
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
let data = Enum::B {
one: 0x11,
two: 0x2233,
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
}
#[test]
fn test_serialize_list_of_lopsided_enums() {
#[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum Enum {
A,
B { one: u8, two: u16 } = 15,
}
println!("{:#?}", Enum::MEMORY_LAYOUT);
let data = [Enum::A, Enum::A];
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!([Enum; 2], buf).unwrap().1, data);
let data = [
Enum::B {
one: 0x11,
two: 0x2233,
},
Enum::B {
one: 0x12,
two: 0x2244,
},
];
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!([Enum; 2], buf).unwrap().1, data);
let data = [
Enum::A,
Enum::B {
one: 0x11,
two: 0x2233,
},
];
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!([Enum; 2], buf).unwrap().1, data);
let data = [
Enum::B {
one: 0x11,
two: 0x2233,
},
Enum::A,
];
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!([Enum; 2], buf).unwrap().1, data);
}
#[test]
fn test_serialize_u8_enum() {
#[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
#[repr(u8)]
enum Enum {
A,
B,
}
println!("{:#?}", Enum::MEMORY_LAYOUT);
let data = Enum::A;
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
let data = Enum::B;
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
}
#[test]
fn test_serialize_corrupted_enum() {
#[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum Enum {
A { one: u32, two: u16 },
}
let data = Enum::A {
one: 0x11111111,
two: 0x22,
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
buf = buf.set(0, 2);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf), None);
}
#[test]
fn test_serialize_nested_enum() {
#[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum Enum {
A { one: u32, two: u16 },
B { one: u8, two: InnerEnum } = 15,
}
#[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
#[repr(C, u16)]
enum InnerEnum {
A(u8),
B { one: u64, two: f64 } = 1000,
C { one: u32, two: u16 },
}
let data = Enum::A {
one: 0x11111111,
two: 0x22,
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
let data = Enum::B {
one: 0x11,
two: InnerEnum::A(0x22),
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
let data = Enum::B {
one: 0x11,
two: InnerEnum::B {
one: 0x2233,
two: 0.123456789,
},
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
let data = Enum::B {
one: 0x11,
two: InnerEnum::C {
one: 0x2233,
two: 56789,
},
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
println!("{:?}", buf.as_ref());
let buf = buf.as_ref();
assert_eq!(deserialize_const!(Enum, buf).unwrap().1, data);
}
#[test]
fn test_adding_enum_field_non_breaking() {
#[derive(Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum Initial {
A { a: u32, b: u8 },
}
#[derive(Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum New {
A { b: u8, a: u32, c: u32 },
}
let data = New::A {
a: 0x11111111,
b: 0x22,
c: 0x33333333,
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
let buf = buf.as_ref();
// The new struct should be able to deserialize into the initial struct
let (_, data2) = deserialize_const!(Initial, buf).unwrap();
assert_eq!(
Initial::A {
a: 0x11111111,
b: 0x22,
},
data2
);
}
#[test]
fn test_adding_enum_variant_non_breaking() {
#[derive(Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum Initial {
A { a: u32, b: u8 },
}
#[derive(Debug, PartialEq, SerializeConst)]
#[repr(C, u8)]
enum New {
#[allow(unused)]
B {
d: u32,
e: u8,
},
A {
c: u32,
b: u8,
a: u32,
},
}
let data = New::A {
a: 0x11111111,
b: 0x22,
c: 0x33333333,
};
let mut buf = ConstVec::new();
buf = serialize_const(&data, buf);
let buf = buf.as_ref();
// The new struct should be able to deserialize into the initial struct
let (_, data2) = deserialize_const!(Initial, buf).unwrap();
assert_eq!(
Initial::A {
a: 0x11111111,
b: 0x22,
},
data2
);
}