pub trait Decoder: Sealed {
type R: Reader;
type C: Config;
// Required methods
fn reader(&mut self) -> &mut Self::R;
fn config(&self) -> &Self::C;
fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError>;
fn unclaim_bytes_read(&mut self, n: usize);
// Provided method
fn claim_container_read<T>(&mut self, len: usize) -> Result<(), DecodeError> { ... }
}
Expand description
Any source that can decode basic types. This type is most notably implemented for Decoder.
Required Associated Types§
Required Methods§
sourcefn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError>
fn claim_bytes_read(&mut self, n: usize) -> Result<(), DecodeError>
Claim that n
bytes are going to be read from the decoder.
This can be used to validate Configuration::Limit<N>()
.
sourcefn unclaim_bytes_read(&mut self, n: usize)
fn unclaim_bytes_read(&mut self, n: usize)
Notify the decoder that n
bytes are being reclaimed.
When decoding container types, a typical implementation would claim to read len * size_of::<T>()
bytes.
This is to ensure that bincode won’t allocate several GB of memory while constructing the container.
Because the implementation claims len * size_of::<T>()
, but then has to decode each T
, this would be marked
as double. This function allows us to un-claim each T
that gets decoded.
We cannot check if len * size_of::<T>()
is valid without claiming it, because this would mean that if you have
a nested container (e.g. Vec<Vec<T>>
), it does not know how much memory is already claimed, and could easily
allocate much more than the user intends.
impl<T: Decode> Decode for Container<T> {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let len = u64::decode(decoder)?;
let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
// Make sure we don't allocate too much memory
decoder.claim_bytes_read(len * core::mem::size_of::<T>());
let mut result = Container::with_capacity(len);
for _ in 0..len {
// un-claim the memory
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
result.push(T::decode(decoder)?)
}
Ok(result)
}
}
impl<'de, T: bincode::BorrowDecode<'de>> bincode::BorrowDecode<'de> for Container<T> {
fn borrow_decode<D: bincode::de::BorrowDecoder<'de>>(
decoder: &mut D,
) -> core::result::Result<Self, bincode::error::DecodeError> {
let len = u64::borrow_decode(decoder)?;
let len: usize = len.try_into().map_err(|_| DecodeError::OutsideUsizeRange(len))?;
// Make sure we don't allocate too much memory
decoder.claim_bytes_read(len * core::mem::size_of::<T>());
let mut result = Container::with_capacity(len);
for _ in 0..len {
// un-claim the memory
decoder.unclaim_bytes_read(core::mem::size_of::<T>());
result.push(T::borrow_decode(decoder)?)
}
Ok(result)
}
}
Provided Methods§
sourcefn claim_container_read<T>(&mut self, len: usize) -> Result<(), DecodeError>
fn claim_container_read<T>(&mut self, len: usize) -> Result<(), DecodeError>
Claim that we’re going to read a container which contains len
entries of T
.
This will correctly handle overflowing if len * size_of::<T>() > usize::max_value