Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/storable/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,29 @@ proptest! {
prop_assert_eq!(v.clone(), Storable::from_bytes(v.to_bytes()));
}

// 2-tuple unbounded roundtrips

#[test]
fn tuple_two_unbounded_elements_roundtrip(v1 in pvec(any::<u8>(), 0..16), v2 in pvec(any::<u8>(), 0..32)) {
// (Vec<u8>, Vec<u8>): both unbounded
let tuple = (v1, v2);
prop_assert_eq!(tuple.clone(), Storable::from_bytes(tuple.to_bytes()));
}

#[test]
fn tuple_fixed_and_unbounded_roundtrip(x in any::<u64>(), v in pvec(any::<u8>(), 0..32)) {
// (u64, Vec<u8>): fixed A, unbounded B — no size_lengths overhead
let tuple = (x, v);
prop_assert_eq!(tuple.clone(), Storable::from_bytes(tuple.to_bytes()));
}

#[test]
fn tuple_unbounded_and_fixed_roundtrip(v in pvec(any::<u8>(), 0..32), x in any::<u64>()) {
// (Vec<u8>, u64): unbounded A, fixed B — size_lengths overhead needed
let tuple = (v, x);
prop_assert_eq!(tuple.clone(), Storable::from_bytes(tuple.to_bytes()));
}

#[test]
fn principal_roundtrip(mut bytes in pvec(any::<u8>(), 0..=28), tag in proptest::prop_oneof![Just(1),Just(2),Just(3),Just(4),Just(7)]) {
bytes.push(tag);
Expand Down
49 changes: 47 additions & 2 deletions src/storable/tuples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,24 @@ where
let b = B::from_bytes(Cow::Borrowed(&bytes[a_max_size..a_max_size + b_len]));
(a, b)
}
_ => todo!("Deserializing tuples with unbounded types is not yet supported."),
Bound::Unbounded => {
let mut offset = 0;
let size_length_a = if A::BOUND.is_fixed_size() {
None
} else {
let lengths = decode_size_lengths(bytes[0], 1);
offset += 1;
Some(lengths[0])
};

let (a, read) = decode_tuple_element::<A>(&bytes[offset..], size_length_a, false);
offset += read;
let (b, read) = decode_tuple_element::<B>(&bytes[offset..], None, true);
offset += read;

debug_assert_eq!(offset, bytes.len());
(a, b)
}
}
}

Expand Down Expand Up @@ -100,7 +117,35 @@ where

bytes
}
_ => todo!("Serializing tuples with unbounded types is not yet supported."),
Bound::Unbounded => {
let a_bytes = a.to_bytes();
let b_bytes = b.to_bytes();
let a_size = a_bytes.len();
let b_size = b_bytes.len();

// If A is variable-size we need a 1B size_lengths header and A's size prefix.
// B is the last element, so its size is always inferred from remaining bytes.
let sizes_overhead = if A::BOUND.is_fixed_size() {
0
} else {
1 + bytes_to_store_size(a_size)
};

let output_size = a_size + b_size + sizes_overhead;
let mut bytes = vec![0; output_size];
let mut offset = 0;

if sizes_overhead != 0 {
bytes[offset] = encode_size_lengths(&[a_size]);
offset += 1;
}

offset += encode_tuple_element::<A>(&mut bytes[offset..], a_bytes.as_ref(), false);
offset += encode_tuple_element::<B>(&mut bytes[offset..], b_bytes.as_ref(), true);

debug_assert_eq!(offset, output_size);
bytes
}
}
}

Expand Down
Loading