Skip to content

Commit 96430c8

Browse files
committed
Add encode_sections() helper
1 parent fd9ec55 commit 96430c8

File tree

1 file changed

+66
-0
lines changed

1 file changed

+66
-0
lines changed

packages/std/src/sections.rs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
use crate::conversion::to_u32;
2+
use crate::errors::StdResult;
3+
14
/// A sections decoder for the special case of two elements
25
#[allow(dead_code)] // used in Wasm and tests only
36
pub fn decode_sections2(data: Vec<u8>) -> (Vec<u8>, Vec<u8>) {
@@ -6,6 +9,33 @@ pub fn decode_sections2(data: Vec<u8>) -> (Vec<u8>, Vec<u8>) {
69
(first, second)
710
}
811

12+
/// Encodes multiple sections of data into one vector.
13+
///
14+
/// Each section is suffixed by a section length encoded as big endian uint32.
15+
/// Using suffixes instead of prefixes allows reading sections in reverse order,
16+
/// such that the first element does not need to be re-allocated if the contract's
17+
/// data structure supports truncation (such as a Rust vector).
18+
///
19+
/// The resulting data looks like this:
20+
///
21+
/// ```ignore
22+
/// section1 || section1_len || section2 || section2_len || section3 || section3_len || …
23+
/// ```
24+
#[allow(dead_code)] // used in Wasm and tests only
25+
pub fn encode_sections(sections: &[Vec<u8>]) -> StdResult<Vec<u8>> {
26+
let mut out_len: usize = sections.iter().map(|section| section.len()).sum();
27+
out_len += 4 * sections.len();
28+
let mut out_data = Vec::with_capacity(out_len);
29+
for section in sections {
30+
let section_len = to_u32(section.len())?.to_be_bytes();
31+
out_data.extend(section);
32+
out_data.extend_from_slice(&section_len);
33+
}
34+
debug_assert_eq!(out_data.len(), out_len);
35+
debug_assert_eq!(out_data.capacity(), out_len);
36+
Ok(out_data)
37+
}
38+
939
/// Splits data into the last section ("tail") and the rest.
1040
/// The tail's length information is cut off, such that it is ready to use.
1141
/// The rest is basically unparsed and contails the lengths of the remaining sections.
@@ -76,4 +106,40 @@ mod tests {
76106
assert_ne!(second.capacity(), original_capacity);
77107
assert_ne!(second.as_ptr(), original_ptr);
78108
}
109+
110+
#[test]
111+
fn encode_sections_works_for_empty_sections() {
112+
let enc = encode_sections(&[]).unwrap();
113+
assert_eq!(enc, b"" as &[u8]);
114+
let enc = encode_sections(&[vec![]]).unwrap();
115+
assert_eq!(enc, b"\0\0\0\0" as &[u8]);
116+
let enc = encode_sections(&[vec![], vec![]]).unwrap();
117+
assert_eq!(enc, b"\0\0\0\0\0\0\0\0" as &[u8]);
118+
let enc = encode_sections(&[vec![], vec![], vec![]]).unwrap();
119+
assert_eq!(enc, b"\0\0\0\0\0\0\0\0\0\0\0\0" as &[u8]);
120+
}
121+
122+
#[test]
123+
fn encode_sections_works_for_one_element() {
124+
let enc = encode_sections(&[]).unwrap();
125+
assert_eq!(enc, b"" as &[u8]);
126+
let enc = encode_sections(&[vec![0xAA]]).unwrap();
127+
assert_eq!(enc, b"\xAA\0\0\0\x01" as &[u8]);
128+
let enc = encode_sections(&[vec![0xAA, 0xBB]]).unwrap();
129+
assert_eq!(enc, b"\xAA\xBB\0\0\0\x02" as &[u8]);
130+
let enc = encode_sections(&[vec![0x9D; 277]]).unwrap();
131+
assert_eq!(enc, b"\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\x9D\0\0\x01\x15" as &[u8]);
132+
}
133+
134+
#[test]
135+
fn encode_sections_works_for_multiple_elements() {
136+
let enc = encode_sections(&[vec![0xAA]]).unwrap();
137+
assert_eq!(enc, b"\xAA\0\0\0\x01" as &[u8]);
138+
let enc = encode_sections(&[vec![0xAA], vec![0xDE, 0xDE]]).unwrap();
139+
assert_eq!(enc, b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02" as &[u8]);
140+
let enc = encode_sections(&[vec![0xAA], vec![0xDE, 0xDE], vec![]]).unwrap();
141+
assert_eq!(enc, b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02\0\0\0\0" as &[u8]);
142+
let enc = encode_sections(&[vec![0xAA], vec![0xDE, 0xDE], vec![], vec![0xFF; 19]]).unwrap();
143+
assert_eq!(enc, b"\xAA\0\0\0\x01\xDE\xDE\0\0\0\x02\0\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\x13" as &[u8]);
144+
}
79145
}

0 commit comments

Comments
 (0)