lib.rs 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937
  1. #![doc = include_str!("../README.md")]
  2. #![warn(missing_docs)]
  3. use std::{char, mem::MaybeUninit};
  4. mod const_buffers;
  5. mod const_vec;
  6. pub use const_buffers::ConstReadBuffer;
  7. pub use const_serialize_macro::SerializeConst;
  8. pub use const_vec::ConstVec;
  9. /// Plain old data for a field. Stores the offset of the field in the struct and the layout of the field.
  10. #[derive(Debug, Copy, Clone)]
  11. pub struct StructFieldLayout {
  12. offset: usize,
  13. layout: Layout,
  14. }
  15. impl StructFieldLayout {
  16. /// Create a new struct field layout
  17. pub const fn new(offset: usize, layout: Layout) -> Self {
  18. Self { offset, layout }
  19. }
  20. }
  21. /// Layout for a struct. The struct layout is just a list of fields with offsets
  22. #[derive(Debug, Copy, Clone)]
  23. pub struct StructLayout {
  24. size: usize,
  25. data: &'static [StructFieldLayout],
  26. }
  27. impl StructLayout {
  28. /// Create a new struct layout
  29. pub const fn new(size: usize, data: &'static [StructFieldLayout]) -> Self {
  30. Self { size, data }
  31. }
  32. }
  33. /// The layout for an enum. The enum layout is just a discriminate size and a tag layout.
  34. #[derive(Debug, Copy, Clone)]
  35. pub struct EnumLayout {
  36. size: usize,
  37. discriminant: PrimitiveLayout,
  38. variants_offset: usize,
  39. variants: &'static [EnumVariant],
  40. }
  41. impl EnumLayout {
  42. /// Create a new enum layout
  43. pub const fn new(
  44. size: usize,
  45. discriminant: PrimitiveLayout,
  46. variants: &'static [EnumVariant],
  47. ) -> Self {
  48. let mut max_align = 1;
  49. let mut i = 0;
  50. while i < variants.len() {
  51. let EnumVariant { align, .. } = &variants[i];
  52. if *align > max_align {
  53. max_align = *align;
  54. }
  55. i += 1;
  56. }
  57. let variants_offset_raw = discriminant.size;
  58. let padding = (max_align - (variants_offset_raw % max_align)) % max_align;
  59. let variants_offset = variants_offset_raw + padding;
  60. assert!(variants_offset % max_align == 0);
  61. Self {
  62. size,
  63. discriminant,
  64. variants_offset,
  65. variants,
  66. }
  67. }
  68. }
  69. /// The layout for an enum variant. The enum variant layout is just a struct layout with a tag and alignment.
  70. #[derive(Debug, Copy, Clone)]
  71. pub struct EnumVariant {
  72. // Note: tags may not be sequential
  73. tag: u32,
  74. data: StructLayout,
  75. align: usize,
  76. }
  77. impl EnumVariant {
  78. /// Create a new enum variant layout
  79. pub const fn new(tag: u32, data: StructLayout, align: usize) -> Self {
  80. Self { tag, data, align }
  81. }
  82. }
  83. /// The layout for a constant sized array. The array layout is just a length and an item layout.
  84. #[derive(Debug, Copy, Clone)]
  85. pub struct ListLayout {
  86. len: usize,
  87. item_layout: &'static Layout,
  88. }
  89. impl ListLayout {
  90. /// Create a new list layout
  91. pub const fn new(len: usize, item_layout: &'static Layout) -> Self {
  92. Self { len, item_layout }
  93. }
  94. }
  95. /// The layout for a primitive type. The bytes will be reversed if the target is big endian.
  96. #[derive(Debug, Copy, Clone)]
  97. pub struct PrimitiveLayout {
  98. size: usize,
  99. }
  100. impl PrimitiveLayout {
  101. /// Create a new primitive layout
  102. pub const fn new(size: usize) -> Self {
  103. Self { size }
  104. }
  105. }
  106. /// The layout for a type. This layout defines a sequence of locations and reversed or not bytes. These bytes will be copied from during serialization and copied into during deserialization.
  107. #[derive(Debug, Copy, Clone)]
  108. pub enum Layout {
  109. /// An enum layout
  110. Enum(EnumLayout),
  111. /// A struct layout
  112. Struct(StructLayout),
  113. /// A list layout
  114. List(ListLayout),
  115. /// A primitive layout
  116. Primitive(PrimitiveLayout),
  117. }
  118. impl Layout {
  119. /// The size of the type in bytes.
  120. const fn size(&self) -> usize {
  121. match self {
  122. Layout::Enum(layout) => layout.size,
  123. Layout::Struct(layout) => layout.size,
  124. Layout::List(layout) => layout.len * layout.item_layout.size(),
  125. Layout::Primitive(layout) => layout.size,
  126. }
  127. }
  128. }
  129. /// A trait for types that can be serialized and deserialized in const.
  130. ///
  131. /// # Safety
  132. /// The layout must accurately describe the memory layout of the type
  133. pub unsafe trait SerializeConst: Sized {
  134. /// The memory layout of the type. This type must have plain old data; no pointers or references.
  135. const MEMORY_LAYOUT: Layout;
  136. /// Assert that the memory layout of the type is the same as the size of the type
  137. const _ASSERT: () = assert!(Self::MEMORY_LAYOUT.size() == std::mem::size_of::<Self>());
  138. }
  139. macro_rules! impl_serialize_const {
  140. ($type:ty) => {
  141. unsafe impl SerializeConst for $type {
  142. const MEMORY_LAYOUT: Layout = Layout::Primitive(PrimitiveLayout {
  143. size: std::mem::size_of::<$type>(),
  144. });
  145. }
  146. };
  147. }
  148. impl_serialize_const!(u8);
  149. impl_serialize_const!(u16);
  150. impl_serialize_const!(u32);
  151. impl_serialize_const!(u64);
  152. impl_serialize_const!(i8);
  153. impl_serialize_const!(i16);
  154. impl_serialize_const!(i32);
  155. impl_serialize_const!(i64);
  156. impl_serialize_const!(bool);
  157. impl_serialize_const!(f32);
  158. impl_serialize_const!(f64);
  159. unsafe impl<const N: usize, T: SerializeConst> SerializeConst for [T; N] {
  160. const MEMORY_LAYOUT: Layout = Layout::List(ListLayout {
  161. len: N,
  162. item_layout: &T::MEMORY_LAYOUT,
  163. });
  164. }
  165. macro_rules! impl_serialize_const_tuple {
  166. ($($generic:ident: $generic_number:expr),*) => {
  167. impl_serialize_const_tuple!(@impl ($($generic,)*) = $($generic: $generic_number),*);
  168. };
  169. (@impl $inner:ty = $($generic:ident: $generic_number:expr),*) => {
  170. unsafe impl<$($generic: SerializeConst),*> SerializeConst for ($($generic,)*) {
  171. const MEMORY_LAYOUT: Layout = {
  172. Layout::Struct(StructLayout {
  173. size: std::mem::size_of::<($($generic,)*)>(),
  174. data: &[
  175. $(
  176. StructFieldLayout::new(std::mem::offset_of!($inner, $generic_number), $generic::MEMORY_LAYOUT),
  177. )*
  178. ],
  179. })
  180. };
  181. }
  182. };
  183. }
  184. impl_serialize_const_tuple!(T1: 0);
  185. impl_serialize_const_tuple!(T1: 0, T2: 1);
  186. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2);
  187. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3);
  188. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4);
  189. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5);
  190. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6);
  191. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7);
  192. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7, T9: 8);
  193. impl_serialize_const_tuple!(T1: 0, T2: 1, T3: 2, T4: 3, T5: 4, T6: 5, T7: 6, T8: 7, T9: 8, T10: 9);
  194. const MAX_STR_SIZE: usize = 256;
  195. /// A string that is stored in a constant sized buffer that can be serialized and deserialized at compile time
  196. #[derive(PartialEq, PartialOrd, Clone, Copy, Hash)]
  197. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
  198. pub struct ConstStr {
  199. #[cfg_attr(feature = "serde", serde(with = "serde_bytes"))]
  200. bytes: [u8; MAX_STR_SIZE],
  201. len: u32,
  202. }
  203. #[cfg(feature = "serde")]
  204. mod serde_bytes {
  205. use serde::{Deserialize, Serializer};
  206. pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
  207. where
  208. S: Serializer,
  209. {
  210. serializer.serialize_bytes(bytes)
  211. }
  212. pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; super::MAX_STR_SIZE], D::Error>
  213. where
  214. D: serde::Deserializer<'de>,
  215. {
  216. let bytes = Vec::<u8>::deserialize(deserializer)?;
  217. bytes
  218. .try_into()
  219. .map_err(|_| serde::de::Error::custom("Failed to convert bytes to a fixed size array"))
  220. }
  221. }
  222. unsafe impl SerializeConst for ConstStr {
  223. const MEMORY_LAYOUT: Layout = Layout::Struct(StructLayout {
  224. size: std::mem::size_of::<Self>(),
  225. data: &[
  226. StructFieldLayout::new(
  227. std::mem::offset_of!(Self, bytes),
  228. Layout::List(ListLayout {
  229. len: MAX_STR_SIZE,
  230. item_layout: &Layout::Primitive(PrimitiveLayout {
  231. size: std::mem::size_of::<u8>(),
  232. }),
  233. }),
  234. ),
  235. StructFieldLayout::new(
  236. std::mem::offset_of!(Self, len),
  237. Layout::Primitive(PrimitiveLayout {
  238. size: std::mem::size_of::<u32>(),
  239. }),
  240. ),
  241. ],
  242. });
  243. }
  244. impl ConstStr {
  245. /// Create a new constant string
  246. pub const fn new(s: &str) -> Self {
  247. let str_bytes = s.as_bytes();
  248. let mut bytes = [0; MAX_STR_SIZE];
  249. let mut i = 0;
  250. while i < str_bytes.len() {
  251. bytes[i] = str_bytes[i];
  252. i += 1;
  253. }
  254. Self {
  255. bytes,
  256. len: str_bytes.len() as u32,
  257. }
  258. }
  259. /// Get a reference to the string
  260. pub const fn as_str(&self) -> &str {
  261. let str_bytes = self.bytes.split_at(self.len as usize).0;
  262. match std::str::from_utf8(str_bytes) {
  263. Ok(s) => s,
  264. Err(_) => panic!(
  265. "Invalid utf8; ConstStr should only ever be constructed from valid utf8 strings"
  266. ),
  267. }
  268. }
  269. /// Get the length of the string
  270. pub const fn len(&self) -> usize {
  271. self.len as usize
  272. }
  273. /// Check if the string is empty
  274. pub const fn is_empty(&self) -> bool {
  275. self.len == 0
  276. }
  277. /// Push a character onto the string
  278. pub const fn push(self, byte: char) -> Self {
  279. assert!(byte.is_ascii(), "Only ASCII bytes are supported");
  280. let (bytes, len) = char_to_bytes(byte);
  281. let (str, _) = bytes.split_at(len);
  282. let Ok(str) = std::str::from_utf8(str) else {
  283. panic!("Invalid utf8; char_to_bytes should always return valid utf8 bytes")
  284. };
  285. self.push_str(str)
  286. }
  287. /// Push a str onto the string
  288. pub const fn push_str(self, str: &str) -> Self {
  289. let Self { mut bytes, len } = self;
  290. assert!(
  291. str.len() + len as usize <= MAX_STR_SIZE,
  292. "String is too long"
  293. );
  294. let str_bytes = str.as_bytes();
  295. let new_len = len as usize + str_bytes.len();
  296. let mut i = 0;
  297. while i < str_bytes.len() {
  298. bytes[len as usize + i] = str_bytes[i];
  299. i += 1;
  300. }
  301. Self {
  302. bytes,
  303. len: new_len as u32,
  304. }
  305. }
  306. /// Split the string at a byte index. The byte index must be a char boundary
  307. pub const fn split_at(self, index: usize) -> (Self, Self) {
  308. let (left, right) = self.bytes.split_at(index);
  309. let left = match std::str::from_utf8(left) {
  310. Ok(s) => s,
  311. Err(_) => {
  312. panic!("Invalid utf8; you cannot split at a byte that is not a char boundary")
  313. }
  314. };
  315. let right = match std::str::from_utf8(right) {
  316. Ok(s) => s,
  317. Err(_) => {
  318. panic!("Invalid utf8; you cannot split at a byte that is not a char boundary")
  319. }
  320. };
  321. (Self::new(left), Self::new(right))
  322. }
  323. /// Split the string at the last occurrence of a character
  324. pub const fn rsplit_once(&self, char: char) -> Option<(Self, Self)> {
  325. let str = self.as_str();
  326. let mut index = str.len() - 1;
  327. // First find the bytes we are searching for
  328. let (char_bytes, len) = char_to_bytes(char);
  329. let (char_bytes, _) = char_bytes.split_at(len);
  330. let bytes = str.as_bytes();
  331. // Then walk backwards from the end of the string
  332. loop {
  333. let byte = bytes[index];
  334. // Look for char boundaries in the string and check if the bytes match
  335. if let Some(char_boundary_len) = utf8_char_boundary_to_char_len(byte) {
  336. // Split up the string into three sections: [before_char, in_char, after_char]
  337. let (before_char, after_index) = bytes.split_at(index);
  338. let (in_char, after_char) = after_index.split_at(char_boundary_len as usize);
  339. if in_char.len() != char_boundary_len as usize {
  340. panic!("in_char.len() should always be equal to char_boundary_len as usize")
  341. }
  342. // Check if the bytes for the current char and the target char match
  343. let mut in_char_eq = true;
  344. let mut i = 0;
  345. let min_len = if in_char.len() < char_bytes.len() {
  346. in_char.len()
  347. } else {
  348. char_bytes.len()
  349. };
  350. while i < min_len {
  351. in_char_eq &= in_char[i] == char_bytes[i];
  352. i += 1;
  353. }
  354. // If they do, convert the bytes to strings and return the split strings
  355. if in_char_eq {
  356. let Ok(before_char_str) = std::str::from_utf8(before_char) else {
  357. panic!("Invalid utf8; utf8_char_boundary_to_char_len should only return Some when the byte is a character boundary")
  358. };
  359. let Ok(after_char_str) = std::str::from_utf8(after_char) else {
  360. panic!("Invalid utf8; utf8_char_boundary_to_char_len should only return Some when the byte is a character boundary")
  361. };
  362. return Some((Self::new(before_char_str), Self::new(after_char_str)));
  363. }
  364. }
  365. match index.checked_sub(1) {
  366. Some(new_index) => index = new_index,
  367. None => return None,
  368. }
  369. }
  370. }
  371. /// Split the string at the first occurrence of a character
  372. pub const fn split_once(&self, char: char) -> Option<(Self, Self)> {
  373. let str = self.as_str();
  374. let mut index = 0;
  375. // First find the bytes we are searching for
  376. let (char_bytes, len) = char_to_bytes(char);
  377. let (char_bytes, _) = char_bytes.split_at(len);
  378. let bytes = str.as_bytes();
  379. // Then walk forwards from the start of the string
  380. while index < bytes.len() {
  381. let byte = bytes[index];
  382. // Look for char boundaries in the string and check if the bytes match
  383. if let Some(char_boundary_len) = utf8_char_boundary_to_char_len(byte) {
  384. // Split up the string into three sections: [before_char, in_char, after_char]
  385. let (before_char, after_index) = bytes.split_at(index);
  386. let (in_char, after_char) = after_index.split_at(char_boundary_len as usize);
  387. if in_char.len() != char_boundary_len as usize {
  388. panic!("in_char.len() should always be equal to char_boundary_len as usize")
  389. }
  390. // Check if the bytes for the current char and the target char match
  391. let mut in_char_eq = true;
  392. let mut i = 0;
  393. let min_len = if in_char.len() < char_bytes.len() {
  394. in_char.len()
  395. } else {
  396. char_bytes.len()
  397. };
  398. while i < min_len {
  399. in_char_eq &= in_char[i] == char_bytes[i];
  400. i += 1;
  401. }
  402. // If they do, convert the bytes to strings and return the split strings
  403. if in_char_eq {
  404. let Ok(before_char_str) = std::str::from_utf8(before_char) else {
  405. panic!("Invalid utf8; utf8_char_boundary_to_char_len should only return Some when the byte is a character boundary")
  406. };
  407. let Ok(after_char_str) = std::str::from_utf8(after_char) else {
  408. panic!("Invalid utf8; utf8_char_boundary_to_char_len should only return Some when the byte is a character boundary")
  409. };
  410. return Some((Self::new(before_char_str), Self::new(after_char_str)));
  411. }
  412. }
  413. index += 1
  414. }
  415. None
  416. }
  417. }
  418. impl std::fmt::Debug for ConstStr {
  419. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  420. write!(f, "{:?}", self.as_str())
  421. }
  422. }
  423. #[test]
  424. fn test_rsplit_once() {
  425. let str = ConstStr::new("hello world");
  426. assert_eq!(
  427. str.rsplit_once(' '),
  428. Some((ConstStr::new("hello"), ConstStr::new("world")))
  429. );
  430. let unicode_str = ConstStr::new("hi😀hello😀world😀world");
  431. assert_eq!(
  432. unicode_str.rsplit_once('😀'),
  433. Some((ConstStr::new("hi😀hello😀world"), ConstStr::new("world")))
  434. );
  435. assert_eq!(unicode_str.rsplit_once('❌'), None);
  436. for _ in 0..100 {
  437. let random_str: String = (0..rand::random::<u8>() % 50)
  438. .map(|_| rand::random::<char>())
  439. .collect();
  440. let konst = ConstStr::new(&random_str);
  441. let mut seen_chars = std::collections::HashSet::new();
  442. for char in random_str.chars().rev() {
  443. let (char_bytes, len) = char_to_bytes(char);
  444. let char_bytes = &char_bytes[..len];
  445. assert_eq!(char_bytes, char.to_string().as_bytes());
  446. if seen_chars.contains(&char) {
  447. continue;
  448. }
  449. seen_chars.insert(char);
  450. let (correct_left, correct_right) = random_str.rsplit_once(char).unwrap();
  451. let (left, right) = konst.rsplit_once(char).unwrap();
  452. println!("splitting {random_str:?} at {char:?}");
  453. assert_eq!(left.as_str(), correct_left);
  454. assert_eq!(right.as_str(), correct_right);
  455. }
  456. }
  457. }
  458. const CONTINUED_CHAR_MASK: u8 = 0b10000000;
  459. const BYTE_CHAR_BOUNDARIES: [u8; 4] = [0b00000000, 0b11000000, 0b11100000, 0b11110000];
  460. // Const version of https://doc.rust-lang.org/src/core/char/methods.rs.html#1765-1797
  461. const fn char_to_bytes(char: char) -> ([u8; 4], usize) {
  462. let code = char as u32;
  463. let len = char.len_utf8();
  464. let mut bytes = [0; 4];
  465. match len {
  466. 1 => {
  467. bytes[0] = code as u8;
  468. }
  469. 2 => {
  470. bytes[0] = (code >> 6 & 0x1F) as u8 | BYTE_CHAR_BOUNDARIES[1];
  471. bytes[1] = (code & 0x3F) as u8 | CONTINUED_CHAR_MASK;
  472. }
  473. 3 => {
  474. bytes[0] = (code >> 12 & 0x0F) as u8 | BYTE_CHAR_BOUNDARIES[2];
  475. bytes[1] = (code >> 6 & 0x3F) as u8 | CONTINUED_CHAR_MASK;
  476. bytes[2] = (code & 0x3F) as u8 | CONTINUED_CHAR_MASK;
  477. }
  478. 4 => {
  479. bytes[0] = (code >> 18 & 0x07) as u8 | BYTE_CHAR_BOUNDARIES[3];
  480. bytes[1] = (code >> 12 & 0x3F) as u8 | CONTINUED_CHAR_MASK;
  481. bytes[2] = (code >> 6 & 0x3F) as u8 | CONTINUED_CHAR_MASK;
  482. bytes[3] = (code & 0x3F) as u8 | CONTINUED_CHAR_MASK;
  483. }
  484. _ => panic!(
  485. "encode_utf8: need more than 4 bytes to encode the unicode character, but the buffer has 4 bytes"
  486. ),
  487. };
  488. (bytes, len)
  489. }
  490. #[test]
  491. fn fuzz_char_to_bytes() {
  492. use std::char;
  493. for _ in 0..100 {
  494. let char = rand::random::<char>();
  495. let (bytes, len) = char_to_bytes(char);
  496. let str = std::str::from_utf8(&bytes[..len]).unwrap();
  497. assert_eq!(char.to_string(), str);
  498. }
  499. }
  500. const fn utf8_char_boundary_to_char_len(byte: u8) -> Option<u8> {
  501. match byte {
  502. 0b00000000..=0b01111111 => Some(1),
  503. 0b11000000..=0b11011111 => Some(2),
  504. 0b11100000..=0b11101111 => Some(3),
  505. 0b11110000..=0b11111111 => Some(4),
  506. _ => None,
  507. }
  508. }
  509. #[test]
  510. fn fuzz_utf8_byte_to_char_len() {
  511. for _ in 0..100 {
  512. let random_string: String = (0..rand::random::<u8>())
  513. .map(|_| rand::random::<char>())
  514. .collect();
  515. let bytes = random_string.as_bytes();
  516. let chars: std::collections::HashMap<_, _> = random_string.char_indices().collect();
  517. for (i, byte) in bytes.iter().enumerate() {
  518. match utf8_char_boundary_to_char_len(*byte) {
  519. Some(char_len) => {
  520. let char = chars
  521. .get(&i)
  522. .unwrap_or_else(|| panic!("{byte:b} is not a character boundary"));
  523. assert_eq!(char.len_utf8(), char_len as usize);
  524. }
  525. None => {
  526. assert!(!chars.contains_key(&i), "{byte:b} is a character boundary");
  527. }
  528. }
  529. }
  530. }
  531. }
  532. /// Serialize a struct that is stored at the pointer passed in
  533. const fn serialize_const_struct(
  534. ptr: *const (),
  535. mut to: ConstVec<u8>,
  536. layout: &StructLayout,
  537. ) -> ConstVec<u8> {
  538. let mut i = 0;
  539. while i < layout.data.len() {
  540. // Serialize the field at the offset pointer in the struct
  541. let StructFieldLayout { offset, layout } = &layout.data[i];
  542. let field = ptr.wrapping_byte_add(*offset as _);
  543. to = serialize_const_ptr(field, to, layout);
  544. i += 1;
  545. }
  546. to
  547. }
  548. /// Serialize an enum that is stored at the pointer passed in
  549. const fn serialize_const_enum(
  550. ptr: *const (),
  551. mut to: ConstVec<u8>,
  552. layout: &EnumLayout,
  553. ) -> ConstVec<u8> {
  554. let mut discriminant = 0;
  555. let byte_ptr = ptr as *const u8;
  556. let mut offset = 0;
  557. while offset < layout.discriminant.size {
  558. // If the bytes are reversed, walk backwards from the end of the number when pushing bytes
  559. let byte = if cfg!(target_endian = "big") {
  560. unsafe {
  561. byte_ptr
  562. .wrapping_byte_add((layout.discriminant.size - offset - 1) as _)
  563. .read()
  564. }
  565. } else {
  566. unsafe { byte_ptr.wrapping_byte_add(offset as _).read() }
  567. };
  568. to = to.push(byte);
  569. discriminant |= (byte as u32) << (offset * 8);
  570. offset += 1;
  571. }
  572. let mut i = 0;
  573. while i < layout.variants.len() {
  574. // If the variant is the discriminated one, serialize it
  575. let EnumVariant { tag, data, .. } = &layout.variants[i];
  576. if discriminant == *tag {
  577. let data_ptr = ptr.wrapping_byte_offset(layout.variants_offset as _);
  578. to = serialize_const_struct(data_ptr, to, data);
  579. break;
  580. }
  581. i += 1;
  582. }
  583. to
  584. }
  585. /// Serialize a primitive type that is stored at the pointer passed in
  586. const fn serialize_const_primitive(
  587. ptr: *const (),
  588. mut to: ConstVec<u8>,
  589. layout: &PrimitiveLayout,
  590. ) -> ConstVec<u8> {
  591. let ptr = ptr as *const u8;
  592. let mut offset = 0;
  593. while offset < layout.size {
  594. // If the bytes are reversed, walk backwards from the end of the number when pushing bytes
  595. if cfg!(any(target_endian = "big", feature = "test-big-endian")) {
  596. to = to.push(unsafe {
  597. ptr.wrapping_byte_offset((layout.size - offset - 1) as _)
  598. .read()
  599. });
  600. } else {
  601. to = to.push(unsafe { ptr.wrapping_byte_offset(offset as _).read() });
  602. }
  603. offset += 1;
  604. }
  605. to
  606. }
  607. /// Serialize a constant sized array that is stored at the pointer passed in
  608. const fn serialize_const_list(
  609. ptr: *const (),
  610. mut to: ConstVec<u8>,
  611. layout: &ListLayout,
  612. ) -> ConstVec<u8> {
  613. let len = layout.len;
  614. let mut i = 0;
  615. while i < len {
  616. let field = ptr.wrapping_byte_offset((i * layout.item_layout.size()) as _);
  617. to = serialize_const_ptr(field, to, layout.item_layout);
  618. i += 1;
  619. }
  620. to
  621. }
  622. /// Serialize a pointer to a type that is stored at the pointer passed in
  623. const fn serialize_const_ptr(ptr: *const (), to: ConstVec<u8>, layout: &Layout) -> ConstVec<u8> {
  624. match layout {
  625. Layout::Enum(layout) => serialize_const_enum(ptr, to, layout),
  626. Layout::Struct(layout) => serialize_const_struct(ptr, to, layout),
  627. Layout::List(layout) => serialize_const_list(ptr, to, layout),
  628. Layout::Primitive(layout) => serialize_const_primitive(ptr, to, layout),
  629. }
  630. }
  631. /// Serialize a type into a buffer
  632. ///
  633. /// # Example
  634. ///
  635. /// ```rust
  636. /// use const_serialize::{ConstVec, SerializeConst, serialize_const};
  637. ///
  638. /// #[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
  639. /// struct Struct {
  640. /// a: u32,
  641. /// b: u8,
  642. /// c: u32,
  643. /// }
  644. ///
  645. /// let mut buffer = ConstVec::new();
  646. /// buffer = serialize_const(&Struct {
  647. /// a: 0x11111111,
  648. /// b: 0x22,
  649. /// c: 0x33333333,
  650. /// }, buffer);
  651. /// let buf = buffer.read();
  652. /// assert_eq!(buf.as_ref(), &[0x11, 0x11, 0x11, 0x11, 0x22, 0x33, 0x33, 0x33, 0x33]);
  653. /// ```
  654. #[must_use = "The data is serialized into the returned buffer"]
  655. pub const fn serialize_const<T: SerializeConst>(data: &T, to: ConstVec<u8>) -> ConstVec<u8> {
  656. let ptr = data as *const T as *const ();
  657. serialize_const_ptr(ptr, to, &T::MEMORY_LAYOUT)
  658. }
  659. /// Deserialize a primitive type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
  660. const fn deserialize_const_primitive<'a, const N: usize>(
  661. mut from: ConstReadBuffer<'a>,
  662. layout: &PrimitiveLayout,
  663. out: (usize, [MaybeUninit<u8>; N]),
  664. ) -> Option<(ConstReadBuffer<'a>, [MaybeUninit<u8>; N])> {
  665. let (start, mut out) = out;
  666. let mut offset = 0;
  667. while offset < layout.size {
  668. // If the bytes are reversed, walk backwards from the end of the number when filling in bytes
  669. let (from_new, value) = match from.get() {
  670. Some(data) => data,
  671. None => return None,
  672. };
  673. from = from_new;
  674. if cfg!(any(target_endian = "big", feature = "test-big-endian")) {
  675. out[start + layout.size - offset - 1] = MaybeUninit::new(value);
  676. } else {
  677. out[start + offset] = MaybeUninit::new(value);
  678. }
  679. offset += 1;
  680. }
  681. Some((from, out))
  682. }
  683. /// Deserialize a struct type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
  684. const fn deserialize_const_struct<'a, const N: usize>(
  685. mut from: ConstReadBuffer<'a>,
  686. layout: &StructLayout,
  687. out: (usize, [MaybeUninit<u8>; N]),
  688. ) -> Option<(ConstReadBuffer<'a>, [MaybeUninit<u8>; N])> {
  689. let (start, mut out) = out;
  690. let mut i = 0;
  691. while i < layout.data.len() {
  692. // Deserialize the field at the offset pointer in the struct
  693. let StructFieldLayout { offset, layout } = &layout.data[i];
  694. let (new_from, new_out) = match deserialize_const_ptr(from, layout, (start + *offset, out))
  695. {
  696. Some(data) => data,
  697. None => return None,
  698. };
  699. from = new_from;
  700. out = new_out;
  701. i += 1;
  702. }
  703. Some((from, out))
  704. }
  705. /// Deserialize an enum type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
  706. const fn deserialize_const_enum<'a, const N: usize>(
  707. mut from: ConstReadBuffer<'a>,
  708. layout: &EnumLayout,
  709. out: (usize, [MaybeUninit<u8>; N]),
  710. ) -> Option<(ConstReadBuffer<'a>, [MaybeUninit<u8>; N])> {
  711. let (start, mut out) = out;
  712. let mut discriminant = 0;
  713. // First, deserialize the discriminant
  714. let mut offset = 0;
  715. while offset < layout.discriminant.size {
  716. // If the bytes are reversed, walk backwards from the end of the number when filling in bytes
  717. let (from_new, value) = match from.get() {
  718. Some(data) => data,
  719. None => return None,
  720. };
  721. from = from_new;
  722. if cfg!(target_endian = "big") {
  723. out[start + layout.size - offset - 1] = MaybeUninit::new(value);
  724. discriminant |= (value as u32) << ((layout.discriminant.size - offset - 1) * 8);
  725. } else {
  726. out[start + offset] = MaybeUninit::new(value);
  727. discriminant |= (value as u32) << (offset * 8);
  728. }
  729. offset += 1;
  730. }
  731. // Then, deserialize the variant
  732. let mut i = 0;
  733. let mut matched_variant = false;
  734. while i < layout.variants.len() {
  735. // If the variant is the discriminated one, deserialize it
  736. let EnumVariant { tag, data, .. } = &layout.variants[i];
  737. if discriminant == *tag {
  738. let offset = layout.variants_offset;
  739. let (new_from, new_out) =
  740. match deserialize_const_struct(from, data, (start + offset, out)) {
  741. Some(data) => data,
  742. None => return None,
  743. };
  744. from = new_from;
  745. out = new_out;
  746. matched_variant = true;
  747. break;
  748. }
  749. i += 1;
  750. }
  751. if !matched_variant {
  752. return None;
  753. }
  754. Some((from, out))
  755. }
  756. /// Deserialize a list type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
  757. const fn deserialize_const_list<'a, const N: usize>(
  758. mut from: ConstReadBuffer<'a>,
  759. layout: &ListLayout,
  760. out: (usize, [MaybeUninit<u8>; N]),
  761. ) -> Option<(ConstReadBuffer<'a>, [MaybeUninit<u8>; N])> {
  762. let (start, mut out) = out;
  763. let len = layout.len;
  764. let item_layout = layout.item_layout;
  765. let mut i = 0;
  766. while i < len {
  767. let (new_from, new_out) =
  768. match deserialize_const_ptr(from, item_layout, (start + i * item_layout.size(), out)) {
  769. Some(data) => data,
  770. None => return None,
  771. };
  772. from = new_from;
  773. out = new_out;
  774. i += 1;
  775. }
  776. Some((from, out))
  777. }
  778. /// Deserialize a type into the out buffer at the offset passed in. Returns a new version of the buffer with the data added.
  779. const fn deserialize_const_ptr<'a, const N: usize>(
  780. from: ConstReadBuffer<'a>,
  781. layout: &Layout,
  782. out: (usize, [MaybeUninit<u8>; N]),
  783. ) -> Option<(ConstReadBuffer<'a>, [MaybeUninit<u8>; N])> {
  784. match layout {
  785. Layout::Enum(layout) => deserialize_const_enum(from, layout, out),
  786. Layout::Struct(layout) => deserialize_const_struct(from, layout, out),
  787. Layout::List(layout) => deserialize_const_list(from, layout, out),
  788. Layout::Primitive(layout) => deserialize_const_primitive(from, layout, out),
  789. }
  790. }
  791. /// Deserialize a type into the output buffer. Accepts (Type, ConstVec<u8>) as input and returns Option<(ConstReadBuffer, Instance of type)>
  792. ///
  793. /// # Example
  794. /// ```rust
  795. /// # use const_serialize::{deserialize_const, serialize_const, ConstVec, SerializeConst};
  796. /// #[derive(Clone, Copy, Debug, PartialEq, SerializeConst)]
  797. /// struct Struct {
  798. /// a: u32,
  799. /// b: u8,
  800. /// c: u32,
  801. /// d: u32,
  802. /// }
  803. ///
  804. /// let mut buffer = ConstVec::new();
  805. /// buffer = serialize_const(&Struct {
  806. /// a: 0x11111111,
  807. /// b: 0x22,
  808. /// c: 0x33333333,
  809. /// d: 0x44444444,
  810. /// }, buffer);
  811. /// let buf = buffer.read();
  812. /// assert_eq!(deserialize_const!(Struct, buf).unwrap().1, Struct {
  813. /// a: 0x11111111,
  814. /// b: 0x22,
  815. /// c: 0x33333333,
  816. /// d: 0x44444444,
  817. /// });
  818. /// ```
  819. #[macro_export]
  820. macro_rules! deserialize_const {
  821. ($type:ty, $buffer:expr) => {
  822. unsafe {
  823. const __SIZE: usize = std::mem::size_of::<$type>();
  824. $crate::deserialize_const_raw::<__SIZE, $type>($buffer)
  825. }
  826. };
  827. }
  828. /// Deserialize a buffer into a type. This will return None if the buffer doesn't have enough data to fill the type.
  829. /// # Safety
  830. /// N must be `std::mem::size_of::<T>()`
  831. #[must_use = "The data is deserialized from the input buffer"]
  832. pub const unsafe fn deserialize_const_raw<const N: usize, T: SerializeConst>(
  833. from: ConstReadBuffer,
  834. ) -> Option<(ConstReadBuffer, T)> {
  835. // Create uninitized memory with the size of the type
  836. let out = [MaybeUninit::uninit(); N];
  837. // Fill in the bytes into the buffer for the type
  838. let (from, out) = match deserialize_const_ptr(from, &T::MEMORY_LAYOUT, (0, out)) {
  839. Some(data) => data,
  840. None => return None,
  841. };
  842. // Now that the memory is filled in, transmute it into the type
  843. Some((from, unsafe {
  844. std::mem::transmute_copy::<[MaybeUninit<u8>; N], T>(&out)
  845. }))
  846. }
  847. /// Check if the serialized representation of two items are the same
  848. pub const fn serialize_eq<T: SerializeConst>(first: &T, second: &T) -> bool {
  849. let first_serialized = ConstVec::<u8>::new();
  850. let first_serialized = serialize_const(first, first_serialized);
  851. let second_serialized = ConstVec::<u8>::new();
  852. let second_serialized = serialize_const(second, second_serialized);
  853. let first_buf = first_serialized.as_ref();
  854. let second_buf = second_serialized.as_ref();
  855. if first_buf.len() != second_buf.len() {
  856. return false;
  857. }
  858. let mut i = 0;
  859. while i < first_buf.len() {
  860. if first_buf[i] != second_buf[i] {
  861. return false;
  862. }
  863. i += 1;
  864. }
  865. true
  866. }