use std::{ borrow::Borrow, io::{self, Write}, }; use roc_collections::{MutMap, VecMap}; pub fn serialize_slice( slice: &[T], writer: &mut impl Write, written: usize, ) -> io::Result { let alignment = std::mem::align_of::(); let padding_bytes = next_multiple_of(written, alignment) - written; for _ in 0..padding_bytes { writer.write_all(&[0])?; } let bytes_slice = unsafe { slice_as_bytes(slice) }; writer.write_all(bytes_slice)?; Ok(written + padding_bytes + bytes_slice.len()) } pub fn deserialize_slice(bytes: &[u8], length: usize, mut offset: usize) -> (&[T], usize) { let alignment = std::mem::align_of::(); let size = std::mem::size_of::(); offset = next_multiple_of(offset, alignment); let byte_length = length * size; let byte_slice = &bytes[offset..][..byte_length]; let slice = unsafe { std::slice::from_raw_parts(byte_slice.as_ptr() as *const T, length) }; (slice, offset + byte_length) } pub fn deserialize_vec( bytes: &[u8], length: usize, offset: usize, ) -> (Vec, usize) { let (slice, offset) = deserialize_slice(bytes, length, offset); (slice.to_vec(), offset) } #[derive(Copy, Clone)] struct VecSlice { pub start: u32, pub length: u16, _marker: std::marker::PhantomData, } impl VecSlice { const fn len(&self) -> usize { self.length as usize } fn indices(&self) -> std::ops::Range { self.start as usize..(self.start as usize + self.length as usize) } fn extend_new(vec: &mut Vec, it: impl IntoIterator) -> Self { let start = vec.len(); vec.extend(it); let end = vec.len(); Self { start: start as u32, length: (end - start) as u16, _marker: Default::default(), } } } pub fn serialize_slice_of_slices<'a, T, U>( slice_of_slices: &[U], writer: &mut impl Write, written: usize, ) -> io::Result where T: 'a + Copy, U: 'a + Borrow<[T]> + Sized, { let mut item_buf: Vec = Vec::new(); let mut serialized_slices: Vec> = Vec::new(); for slice in slice_of_slices { let slice = VecSlice::extend_new(&mut item_buf, slice.borrow().iter().copied()); serialized_slices.push(slice); } let written = serialize_slice(&serialized_slices, writer, written)?; serialize_slice(&item_buf, writer, written) } pub fn deserialize_slice_of_slices( bytes: &[u8], length: usize, offset: usize, ) -> (Vec, usize) where T: Copy, Container: From>, { let (serialized_slices, offset) = deserialize_slice::>(bytes, length, offset); let (vars_slice, offset) = { let total_items = serialized_slices.iter().map(|s| s.len()).sum(); deserialize_slice::(bytes, total_items, offset) }; let mut slice_of_slices = Vec::with_capacity(length); for slice in serialized_slices { let deserialized_slice = &vars_slice[slice.indices()]; slice_of_slices.push(deserialized_slice.to_vec().into()) } (slice_of_slices, offset) } pub fn serialize_map( map: &MutMap, ser_keys: fn(&[K], &mut W, usize) -> io::Result, ser_values: fn(&[V], &mut W, usize) -> io::Result, writer: &mut W, written: usize, ) -> io::Result { let keys = map.keys().cloned().collect::>(); let values = map.values().cloned().collect::>(); let written = ser_keys(keys.as_slice(), writer, written)?; let written = ser_values(values.as_slice(), writer, written)?; Ok(written) } #[allow(clippy::type_complexity)] pub fn deserialize_map( bytes: &[u8], deser_keys: fn(&[u8], usize, usize) -> (Vec, usize), deser_values: fn(&[u8], usize, usize) -> (Vec, usize), length: usize, offset: usize, ) -> (MutMap, usize) where K: Clone + std::hash::Hash + Eq, V: Clone, { let (keys, offset) = deser_keys(bytes, length, offset); let (values, offset) = deser_values(bytes, length, offset); ( MutMap::from_iter((keys.iter().cloned()).zip(values.iter().cloned())), offset, ) } pub fn serialize_vec_map( map: &VecMap, ser_keys: fn(&[K], &mut W, usize) -> io::Result, ser_values: fn(&[V], &mut W, usize) -> io::Result, writer: &mut W, written: usize, ) -> io::Result { let (keys, values) = map.unzip_slices(); let written = ser_keys(keys, writer, written)?; let written = ser_values(values, writer, written)?; Ok(written) } #[allow(clippy::type_complexity)] pub fn deserialize_vec_map( bytes: &[u8], deser_keys: fn(&[u8], usize, usize) -> (Vec, usize), deser_values: fn(&[u8], usize, usize) -> (Vec, usize), length: usize, offset: usize, ) -> (VecMap, usize) where K: PartialEq, { let (keys, offset) = deser_keys(bytes, length, offset); let (values, offset) = deser_values(bytes, length, offset); (unsafe { VecMap::zip(keys, values) }, offset) } unsafe fn slice_as_bytes(slice: &[T]) -> &[u8] { let ptr = slice.as_ptr(); let byte_length = std::mem::size_of::() * slice.len(); std::slice::from_raw_parts(ptr as *const u8, byte_length) } // TODO check on https://github.com/rust-lang/rust/issues/88581 some time in the future pub const fn next_multiple_of(lhs: usize, rhs: usize) -> usize { match lhs % rhs { 0 => lhs, r => lhs + (rhs - r), } } #[cfg(test)] mod test { use roc_collections::{MutMap, VecMap, VecSet}; use super::{ deserialize_map, deserialize_slice, deserialize_slice_of_slices, deserialize_vec, deserialize_vec_map, serialize_map, serialize_slice, serialize_slice_of_slices, serialize_vec_map, }; #[test] fn serde_empty_slice() { let mut buf = vec![]; serialize_slice(&[] as &[u8], &mut buf, 0).unwrap(); assert!(buf.is_empty()); let (out, size) = deserialize_slice::(&buf, 0, 0); assert!(out.is_empty()); assert_eq!(size, 0); } #[test] fn serde_slice() { let input: &[u64] = &[15u64, 23, 37, 89]; let mut buf = vec![]; serialize_slice(input, &mut buf, 0).unwrap(); assert!(!buf.is_empty()); let (out, size) = deserialize_slice::(&buf, 4, 0); assert_eq!(out, input); assert_eq!(size, 4 * 8); } #[test] fn serde_vec() { let input: &[u64] = &[15u64, 23, 37, 89]; let mut buf = vec![]; serialize_slice(input, &mut buf, 0).unwrap(); assert!(!buf.is_empty()); let (out, size) = deserialize_vec::(&buf, 4, 0); assert_eq!(out, input); assert_eq!(size, buf.len()); } #[test] fn serde_empty_slice_of_slices() { let input: &[&[u64]] = &[]; let mut buf = vec![]; serialize_slice_of_slices(input, &mut buf, 0).unwrap(); assert!(buf.is_empty()); let (out, size) = deserialize_slice_of_slices::>(&buf, 0, 0); assert!(out.is_empty()); assert_eq!(size, 0); } #[test] fn serde_slice_of_slices() { let input: &[&[u64]] = &[&[15, 23, 47], &[61, 72], &[85, 91]]; let mut buf = vec![]; serialize_slice_of_slices(input, &mut buf, 0).unwrap(); assert!(!buf.is_empty()); let (out, size) = deserialize_slice_of_slices::>(&buf, 3, 0); assert_eq!(out, input); assert_eq!(size, buf.len()); } #[test] fn serde_slice_of_slices_into_vec_set() { let input: &[&[u64]] = &[&[15, 23, 47], &[61, 72], &[85, 91]]; let mut buf = vec![]; serialize_slice_of_slices(input, &mut buf, 0).unwrap(); assert!(!buf.is_empty()); let (out, size) = deserialize_slice_of_slices::>(&buf, 3, 0); assert_eq!(size, buf.len()); let mut out = out.into_iter(); assert_eq!(out.next().unwrap().into_vec(), &[15, 23, 47]); assert_eq!(out.next().unwrap().into_vec(), &[61, 72]); assert_eq!(out.next().unwrap().into_vec(), &[85, 91]); assert!(out.next().is_none()); } #[test] fn serde_empty_map() { let input: MutMap = Default::default(); let mut buf = vec![]; serialize_map(&input, serialize_slice, serialize_slice, &mut buf, 0).unwrap(); assert!(buf.is_empty()); let (out, size) = deserialize_map::(&buf, deserialize_vec, deserialize_vec, 0, 0); assert!(out.is_empty()); assert_eq!(size, 0); } #[test] fn serde_map() { let mut input: MutMap> = Default::default(); input.insert(51, vec![15, 23, 37]); input.insert(39, vec![17, 91, 43]); input.insert(82, vec![90, 35, 76]); let mut buf = vec![]; serialize_map( &input, serialize_slice, serialize_slice_of_slices, &mut buf, 0, ) .unwrap(); assert!(!buf.is_empty()); let (out, size) = deserialize_map::>( &buf, deserialize_vec, deserialize_slice_of_slices, 3, 0, ); assert_eq!(out, input); assert_eq!(size, buf.len()); } #[test] fn serde_empty_vec_map() { let input: VecMap = Default::default(); let mut buf = vec![]; serialize_vec_map(&input, serialize_slice, serialize_slice, &mut buf, 0).unwrap(); assert!(buf.is_empty()); let (out, size) = deserialize_vec_map::(&buf, deserialize_vec, deserialize_vec, 0, 0); assert!(out.is_empty()); assert_eq!(size, 0); } #[test] fn serde_vec_map() { let mut input: VecMap> = Default::default(); input.insert(51, vec![15, 23, 37]); input.insert(39, vec![17, 91, 43]); input.insert(82, vec![90, 35, 76]); let mut buf = vec![]; serialize_vec_map( &input, serialize_slice, serialize_slice_of_slices, &mut buf, 0, ) .unwrap(); assert!(!buf.is_empty()); let (out, size) = deserialize_vec_map::>( &buf, deserialize_vec, deserialize_slice_of_slices, 3, 0, ); assert_eq!(out.unzip_slices(), input.unzip_slices()); assert_eq!(size, buf.len()); } }