parity_scale_codec/
encode_append.rsuse core::iter::ExactSizeIterator;
use crate::{
alloc::vec::Vec,
compact::{Compact, CompactLen},
encode_like::EncodeLike,
Decode, Encode, Error,
};
pub trait EncodeAppend {
type Item: Encode;
fn append_or_new<EncodeLikeItem, I>(self_encoded: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
where
I: IntoIterator<Item = EncodeLikeItem>,
EncodeLikeItem: EncodeLike<Self::Item>,
I::IntoIter: ExactSizeIterator;
}
impl<T: Encode> EncodeAppend for Vec<T> {
type Item = T;
fn append_or_new<EncodeLikeItem, I>(self_encoded: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
where
I: IntoIterator<Item = EncodeLikeItem>,
EncodeLikeItem: EncodeLike<Self::Item>,
I::IntoIter: ExactSizeIterator,
{
append_or_new_impl(self_encoded, iter)
}
}
impl<T: Encode> EncodeAppend for crate::alloc::collections::VecDeque<T> {
type Item = T;
fn append_or_new<EncodeLikeItem, I>(self_encoded: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
where
I: IntoIterator<Item = EncodeLikeItem>,
EncodeLikeItem: EncodeLike<Self::Item>,
I::IntoIter: ExactSizeIterator,
{
append_or_new_impl(self_encoded, iter)
}
}
fn append_or_new_impl<Item, I>(mut vec: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
where
Item: Encode,
I: IntoIterator<Item = Item>,
I::IntoIter: ExactSizeIterator,
{
let iter = iter.into_iter();
let items_to_append = iter.len();
if vec.is_empty() {
crate::codec::compact_encode_len_to(&mut vec, items_to_append)?;
} else {
let old_item_count = u32::from(Compact::<u32>::decode(&mut &vec[..])?);
let new_item_count = old_item_count
.checked_add(items_to_append as u32)
.ok_or("cannot append new items into a SCALE-encoded vector: length overflow due to too many items")?;
let old_item_count_encoded_bytesize = Compact::<u32>::compact_len(&old_item_count);
let new_item_count_encoded_bytesize = Compact::<u32>::compact_len(&new_item_count);
if old_item_count_encoded_bytesize == new_item_count_encoded_bytesize {
Compact(new_item_count).using_encoded(|length_encoded| {
vec[..old_item_count_encoded_bytesize].copy_from_slice(length_encoded)
});
} else {
let new_capacity = vec.len().checked_mul(2)
.ok_or("cannot append new items into a SCALE-encoded vector: new vector won't fit in memory")?;
let mut new_vec = Vec::with_capacity(new_capacity);
crate::codec::compact_encode_len_to(&mut new_vec, new_item_count as usize)?;
new_vec.extend_from_slice(&vec[old_item_count_encoded_bytesize..]);
vec = new_vec;
}
}
iter.for_each(|e| e.encode_to(&mut vec));
Ok(vec)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Encode, EncodeLike, Input};
use std::collections::VecDeque;
const TEST_VALUE: u32 = {
#[cfg(not(miri))]
{
1_000_000
}
#[cfg(miri)]
{
1_000
}
};
#[test]
fn vec_encode_append_works() {
let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
<Vec<u32> as EncodeAppend>::append_or_new(encoded, std::iter::once(&v)).unwrap()
});
let decoded = Vec::<u32>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, (0..TEST_VALUE).collect::<Vec<_>>());
}
#[test]
fn vec_encode_append_multiple_items_works() {
let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
<Vec<u32> as EncodeAppend>::append_or_new(encoded, [v, v, v, v]).unwrap()
});
let decoded = Vec::<u32>::decode(&mut &encoded[..]).unwrap();
let expected = (0..TEST_VALUE).fold(Vec::new(), |mut vec, i| {
vec.append(&mut vec![i, i, i, i]);
vec
});
assert_eq!(decoded, expected);
}
#[test]
fn vecdeque_encode_append_works() {
let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
<VecDeque<u32> as EncodeAppend>::append_or_new(encoded, std::iter::once(&v)).unwrap()
});
let decoded = VecDeque::<u32>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, (0..TEST_VALUE).collect::<Vec<_>>());
}
#[test]
fn vecdeque_encode_append_multiple_items_works() {
let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
<VecDeque<u32> as EncodeAppend>::append_or_new(encoded, [v, v, v, v]).unwrap()
});
let decoded = VecDeque::<u32>::decode(&mut &encoded[..]).unwrap();
let expected = (0..TEST_VALUE).fold(Vec::new(), |mut vec, i| {
vec.append(&mut vec![i, i, i, i]);
vec
});
assert_eq!(decoded, expected);
}
#[test]
fn append_non_copyable() {
#[derive(Eq, PartialEq, Debug)]
struct NoCopy {
data: u32,
}
impl EncodeLike for NoCopy {}
impl Encode for NoCopy {
fn encode(&self) -> Vec<u8> {
self.data.encode()
}
}
impl Decode for NoCopy {
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
u32::decode(input).map(|data| Self { data })
}
}
let append = NoCopy { data: 100 };
let data = Vec::new();
let encoded =
<Vec<NoCopy> as EncodeAppend>::append_or_new(data, std::iter::once(&append)).unwrap();
let decoded = <Vec<NoCopy>>::decode(&mut &encoded[..]).unwrap();
assert_eq!(vec![append], decoded);
}
#[test]
fn vec_encode_like_append_works() {
let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
<Vec<u32> as EncodeAppend>::append_or_new(encoded, std::iter::once(Box::new(v)))
.unwrap()
});
let decoded = Vec::<u32>::decode(&mut &encoded[..]).unwrap();
assert_eq!(decoded, (0..TEST_VALUE).collect::<Vec<_>>());
}
}