Skip to content
This repository has been archived by the owner on Mar 20, 2024. It is now read-only.

Serialize vectors of structs #224

Merged
merged 1 commit into from Jul 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
44 changes: 41 additions & 3 deletions language/move-native/src/lib.rs
Expand Up @@ -1435,6 +1435,34 @@ pub(crate) mod conv {
element_ref
}

/// Get a pointer to a possibly-uninitialized element.
pub unsafe fn get_mut_unchecked_raw(&mut self, i: usize) -> *mut AnyValue {
let struct_size = usize::try_from(self.type_.size).expect("overflow");
let vec_capacity = usize::try_from(self.inner.capacity).expect("overflow");

if i >= vec_capacity {
panic!("index out of bounds");
}

let base_ptr = self.inner.ptr;
let offset = i.checked_mul(struct_size).expect("overflow");
let offset = isize::try_from(offset).expect("overflow");
let element_ptr = base_ptr.offset(offset);
let element_ptr = element_ptr as *mut AnyValue;
element_ptr
}

pub unsafe fn set_length(&mut self, len: usize) {
let vec_capacity = usize::try_from(self.inner.capacity).expect("overflow");

if len > vec_capacity {
panic!("index greater than capacity");
}

let len = u64::try_from(len).expect("overflow");
self.inner.length = len;
}

pub unsafe fn push(&mut self, ptr: *mut AnyValue) {
self.maybe_grow();

Expand Down Expand Up @@ -1473,16 +1501,14 @@ pub(crate) mod conv {

/// This is approximately like `RawVec::grow_amortized`.
///
/// With no `reserve_exact` feature in Move, this always produces
/// power-of-two capacity.
/// It always produces a power-of-two capacity.
#[cold]
pub unsafe fn grow_amortized(&mut self) {
let struct_size = usize::try_from(self.type_.size).expect("overflow");
let struct_align = usize::try_from(self.type_.alignment).expect("overflow");
let vec_len = usize::try_from(self.inner.length).expect("overflow");
let vec_cap = usize::try_from(self.inner.capacity).expect("overflow");

assert!(struct_size != 0); // can't handle ZSTs
assert_eq!(vec_len, vec_cap);

// Same as RawVec
Expand All @@ -1496,8 +1522,20 @@ pub(crate) mod conv {

let new_cap = vec_cap.checked_mul(2).expect("overflow");
let new_cap = core::cmp::max(new_cap, min_non_zero_cap);

self.reserve_exact(new_cap);
}

pub unsafe fn reserve_exact(&mut self, new_cap: usize) {
let struct_size = usize::try_from(self.type_.size).expect("overflow");
let struct_align = usize::try_from(self.type_.alignment).expect("overflow");
let vec_len = usize::try_from(self.inner.length).expect("overflow");
let vec_cap = usize::try_from(self.inner.capacity).expect("overflow");
let new_cap_u64 = u64::try_from(new_cap).expect("overflow");

assert!(struct_size != 0); // can't handle ZSTs
assert!(new_cap >= vec_cap);

let old_vec_byte_size = vec_cap.checked_mul(struct_size).expect("overflow");
let new_vec_byte_size = new_cap.checked_mul(struct_size).expect("overflow");
let new_layout = alloc::alloc::Layout::from_size_align(new_vec_byte_size, struct_align)
Expand Down
46 changes: 41 additions & 5 deletions language/move-native/src/serialization.rs
Expand Up @@ -78,6 +78,10 @@ pub unsafe fn deserialize(type_v: &MoveType, bytes: &MoveByteVector, v: *mut Any
}

unsafe fn deserialize_from_slice(type_v: &MoveType, bytes: &mut &[u8], v: *mut AnyValue) {
// fixme mecause these destination pointers are all uninitialized,
// it's probably best to use ptr::write to write all of them,
// just like in the struct case, since ptr::write is guaranteed
// not to read from the destination.
let v = raw_borrow_move_value_as_rust_value(type_v, v);
match v {
RawBorrowedTypedMoveValue::Bool(vptr) => {
Expand Down Expand Up @@ -168,7 +172,13 @@ unsafe fn serialize_vector(type_elt: &MoveType, v: &MoveUntypedVector) -> Vec<u8
buf
}
TypedMoveBorrowedRustVec::Struct(v) => {
todo!()
let len: u32 = v.inner.length.try_into().expect("overlong vector");
let mut buf = borsh_to_vec(&len);
for elt in v.iter() {
let mut elt_buf = serialize_struct_with_type_info(v.type_, elt);
buf.append(&mut elt_buf);
}
buf
}
TypedMoveBorrowedRustVec::Reference(_, _) => {
todo!("impossible case?");
Expand All @@ -177,6 +187,8 @@ unsafe fn serialize_vector(type_elt: &MoveType, v: &MoveUntypedVector) -> Vec<u8
}

unsafe fn deserialize_vector(type_elt: &MoveType, bytes: &mut &[u8]) -> MoveUntypedVector {
// fixme this should probably create a MoveUntypedVector then
// call borrow_typed_move_vec_as_rust_vec_mut, then match on that.
match type_elt.type_desc {
TypeDesc::Bool => {
let v: Vec<bool> = borsh_from_slice(bytes);
Expand Down Expand Up @@ -230,19 +242,43 @@ unsafe fn deserialize_vector(type_elt: &MoveType, bytes: &mut &[u8]) -> MoveUnty
rust_vec_to_move_vec(v)
}
TypeDesc::Struct => {
todo!()
// This is going to create a new vector with correct pointer alignment,
// reserve space for all elements.
// deserialize each element directly into the vector,
// then set the final length of the vector.

let structinfo = &(*type_elt.type_info).struct_;
let len: u32 = borsh_from_slice(bytes);
let len: usize = len as usize;
let mut v: MoveUntypedVector = crate::std::vector::empty(&type_elt);
let mut vb = MoveBorrowedRustVecOfStructMut {
inner: &mut v,
name: type_elt.name,
type_: structinfo,
};
vb.reserve_exact(len);
for i in 0..len {
let eltptr = vb.get_mut_unchecked_raw(i);
deserialize_struct(type_elt, bytes, eltptr);
}
vb.set_length(len);
v
}
TypeDesc::Reference => {
todo!("impossible case?");
}
}
}

// fixme this allocates more than it should
unsafe fn serialize_struct(t: &MoveType, v: &AnyValue) -> Vec<u8> {
let mut buf = Vec::new();
let structinfo = &(*(t.type_info)).struct_;
for (ft, fv, _) in walk_struct_fields(structinfo, v) {
serialize_struct_with_type_info(structinfo, v)
}

// fixme this allocates more than it should
unsafe fn serialize_struct_with_type_info(t: &StructTypeInfo, v: &AnyValue) -> Vec<u8> {
let mut buf = Vec::new();
for (ft, fv, _) in walk_struct_fields(t, v) {
let field_buf = serialize(ft, fv);
let mut field_buf = move_byte_vec_to_rust_vec(field_buf);
buf.append(&mut field_buf);
Expand Down