use alloc::vec::Vec;
use bincode::{
de::{read::Reader, Decoder},
error::DecodeError,
Decode,
};
const N_MAX_SECTION_PREALLOC: usize = 4096;
const N_MAX_BYTES_CHUNK: usize = 64 * 1024;
fn decode_section_length<Context, D: Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<usize, DecodeError> {
let length: u64 = Decode::decode(decoder)?;
usize::try_from(length).map_err(|_| DecodeError::OutsideUsizeRange(length))
}
fn reserve_capped<T>(vec: &mut Vec<T>, length: usize) -> Result<(), DecodeError> {
vec.try_reserve(length.min(N_MAX_SECTION_PREALLOC))
.map_err(|_| DecodeError::Other("rwasm: failed to allocate section"))
}
pub(crate) fn decode_section_vec<Context, T, D>(decoder: &mut D) -> Result<Vec<T>, DecodeError>
where
T: Decode<Context>,
D: Decoder<Context = Context>,
{
let length = decode_section_length(decoder)?;
decoder.claim_container_read::<T>(length)?;
let mut items = Vec::new();
reserve_capped(&mut items, length)?;
for _ in 0..length {
decoder.unclaim_bytes_read(size_of::<T>());
items.push(T::decode(decoder)?);
}
Ok(items)
}
pub(crate) fn decode_section_bytes<Context, D: Decoder<Context = Context>>(
decoder: &mut D,
) -> Result<Vec<u8>, DecodeError> {
let length = decode_section_length(decoder)?;
decoder.claim_container_read::<u8>(length)?;
let mut bytes = Vec::new();
let mut filled = 0;
while filled < length {
let target = length.min(filled + N_MAX_BYTES_CHUNK);
bytes
.try_reserve(target - filled)
.map_err(|_| DecodeError::Other("rwasm: failed to allocate section"))?;
bytes.resize(target, 0);
decoder.reader().read(&mut bytes[filled..target])?;
filled = target;
}
Ok(bytes)
}