mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 08:17:40 +03:00
add Subs (de)serialization
This commit is contained in:
parent
a601b93a46
commit
c7656955f8
@ -86,6 +86,14 @@ impl SubsHeader {
|
||||
variable_slices: subs.variable_slices.len(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_array(self) -> [u8; std::mem::size_of::<Self>()] {
|
||||
unsafe { std::mem::transmute(self) }
|
||||
}
|
||||
|
||||
fn from_array(array: [u8; std::mem::size_of::<Self>()]) -> Self {
|
||||
unsafe { std::mem::transmute(array) }
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn slice_as_bytes<T>(slice: &[T]) -> &[u8] {
|
||||
@ -95,6 +103,159 @@ unsafe fn slice_as_bytes<T>(slice: &[T]) -> &[u8] {
|
||||
unsafe { std::slice::from_raw_parts(ptr as *const u8, byte_length) }
|
||||
}
|
||||
|
||||
fn round_to_multiple_of(value: usize, base: usize) -> usize {
|
||||
(value + (base - 1)) / base * base
|
||||
}
|
||||
|
||||
impl Subs {
|
||||
pub fn serialize(&self, writer: &mut impl std::io::Write) -> std::io::Result<usize> {
|
||||
let mut written = 0;
|
||||
|
||||
let header = SubsHeader::from_subs(self).to_array();
|
||||
written += header.len();
|
||||
writer.write_all(&header)?;
|
||||
|
||||
written = Self::serialize_unification_table(&self.utable, writer, written)?;
|
||||
|
||||
written = Self::serialize_slice(&self.variables, writer, written)?;
|
||||
written = Self::serialize_slice(&self.tag_names, writer, written)?;
|
||||
written = Self::serialize_slice(&self.field_names, writer, written)?;
|
||||
written = Self::serialize_slice(&self.record_fields, writer, written)?;
|
||||
written = Self::serialize_slice(&self.variable_slices, writer, written)?;
|
||||
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
fn serialize_unification_table(
|
||||
utable: &UnificationTable<InPlace<Variable>>,
|
||||
writer: &mut impl std::io::Write,
|
||||
mut written: usize,
|
||||
) -> std::io::Result<usize> {
|
||||
for i in 0..utable.len() {
|
||||
let var = unsafe { Variable::from_index(i as u32) };
|
||||
|
||||
let desc = if utable.is_redirect(var) {
|
||||
let root = utable.get_root_key_without_compacting(var);
|
||||
|
||||
// our strategy for a redirect; rank is max, mark is max, copy stores the var
|
||||
Descriptor {
|
||||
content: Content::Error,
|
||||
rank: Rank(u32::MAX),
|
||||
mark: Mark(i32::MAX),
|
||||
copy: root.into(),
|
||||
}
|
||||
} else {
|
||||
utable.probe_value_without_compacting(var)
|
||||
};
|
||||
|
||||
let bytes: [u8; std::mem::size_of::<Descriptor>()] =
|
||||
unsafe { std::mem::transmute(desc) };
|
||||
written += bytes.len();
|
||||
writer.write_all(&bytes)?;
|
||||
}
|
||||
|
||||
Ok(written)
|
||||
}
|
||||
|
||||
fn serialize_slice<T>(
|
||||
slice: &[T],
|
||||
writer: &mut impl std::io::Write,
|
||||
written: usize,
|
||||
) -> std::io::Result<usize> {
|
||||
let alignment = std::mem::align_of::<T>();
|
||||
let padding_bytes = round_to_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(bytes: &[u8]) -> Self {
|
||||
use std::convert::TryInto;
|
||||
|
||||
let mut offset = 0;
|
||||
let header_slice = &bytes[..std::mem::size_of::<SubsHeader>()];
|
||||
offset += header_slice.len();
|
||||
let header = SubsHeader::from_array(header_slice.try_into().unwrap());
|
||||
|
||||
let (utable, offset) = Self::deserialize_unification_table(bytes, header.utable, offset);
|
||||
|
||||
let (variables, offset) = Self::deserialize_slice(bytes, header.variables, offset);
|
||||
let (tag_names, offset) = Self::deserialize_slice(bytes, header.tag_names, offset);
|
||||
let (field_names, offset) = Self::deserialize_slice(bytes, header.field_names, offset);
|
||||
let (record_fields, offset) = Self::deserialize_slice(bytes, header.record_fields, offset);
|
||||
let (variable_slices, _) = Self::deserialize_slice(bytes, header.variable_slices, offset);
|
||||
|
||||
Self {
|
||||
utable,
|
||||
variables: variables.to_vec(),
|
||||
tag_names: tag_names.to_vec(),
|
||||
field_names: field_names.to_vec(),
|
||||
record_fields: record_fields.to_vec(),
|
||||
variable_slices: variable_slices.to_vec(),
|
||||
tag_name_cache: Default::default(),
|
||||
problems: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_unification_table(
|
||||
bytes: &[u8],
|
||||
length: usize,
|
||||
offset: usize,
|
||||
) -> (UnificationTable<InPlace<Variable>>, usize) {
|
||||
let alignment = std::mem::align_of::<Descriptor>();
|
||||
let size = std::mem::size_of::<Descriptor>();
|
||||
debug_assert_eq!(offset, round_to_multiple_of(offset, alignment));
|
||||
|
||||
let mut utable = UnificationTable::default();
|
||||
utable.reserve(length);
|
||||
|
||||
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 Descriptor, length) };
|
||||
|
||||
let mut roots = Vec::new();
|
||||
|
||||
for desc in slice {
|
||||
let var = utable.new_key(*desc);
|
||||
|
||||
if desc.rank == Rank(u32::MAX) && desc.mark == Mark(i32::MAX) {
|
||||
let root = desc.copy.into_variable().unwrap();
|
||||
|
||||
roots.push((var, root));
|
||||
}
|
||||
}
|
||||
|
||||
for (var, root) in roots {
|
||||
let desc = utable.probe_value_without_compacting(root);
|
||||
utable.unify_roots(var, root, desc)
|
||||
}
|
||||
|
||||
(utable, offset + byte_length)
|
||||
}
|
||||
|
||||
fn deserialize_slice<T>(bytes: &[u8], length: usize, mut offset: usize) -> (&[T], usize) {
|
||||
let alignment = std::mem::align_of::<T>();
|
||||
let size = std::mem::size_of::<T>();
|
||||
|
||||
offset = round_to_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)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Subs {
|
||||
utable: UnificationTable<InPlace<Variable>>,
|
||||
@ -1757,7 +1918,7 @@ impl From<usize> for Rank {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Descriptor {
|
||||
pub content: Content,
|
||||
pub rank: Rank,
|
||||
|
Loading…
Reference in New Issue
Block a user