parity_scale_codec/
encode_append.rs

1// Copyright 2019 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use core::iter::ExactSizeIterator;
16
17use crate::{
18	alloc::vec::Vec,
19	compact::{Compact, CompactLen},
20	encode_like::EncodeLike,
21	Decode, Encode, Error,
22};
23
24/// Trait that allows to append items to an encoded representation without
25/// decoding all previous added items.
26pub trait EncodeAppend {
27	/// The item that will be appended.
28	type Item: Encode;
29
30	/// Append all items in `iter` to the given `self_encoded` representation
31	/// or if `self_encoded` value is empty, `iter` is encoded to the `Self` representation.
32	///
33	/// # Example
34	///
35	/// ```
36	/// # use parity_scale_codec::EncodeAppend;
37	///
38	/// // Some encoded data
39	/// let data = Vec::new();
40	///
41	/// let item = 8u32;
42	/// let encoded = <Vec<u32> as EncodeAppend>::append_or_new(data, std::iter::once(&item)).expect("Adds new element");
43	///
44	/// // Add multiple element
45	/// <Vec<u32> as EncodeAppend>::append_or_new(encoded, &[700u32, 800u32, 10u32]).expect("Adds new elements");
46	/// ```
47	fn append_or_new<EncodeLikeItem, I>(self_encoded: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
48	where
49		I: IntoIterator<Item = EncodeLikeItem>,
50		EncodeLikeItem: EncodeLike<Self::Item>,
51		I::IntoIter: ExactSizeIterator;
52}
53
54impl<T: Encode> EncodeAppend for Vec<T> {
55	type Item = T;
56
57	fn append_or_new<EncodeLikeItem, I>(self_encoded: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
58	where
59		I: IntoIterator<Item = EncodeLikeItem>,
60		EncodeLikeItem: EncodeLike<Self::Item>,
61		I::IntoIter: ExactSizeIterator,
62	{
63		append_or_new_impl(self_encoded, iter)
64	}
65}
66
67impl<T: Encode> EncodeAppend for crate::alloc::collections::VecDeque<T> {
68	type Item = T;
69
70	fn append_or_new<EncodeLikeItem, I>(self_encoded: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
71	where
72		I: IntoIterator<Item = EncodeLikeItem>,
73		EncodeLikeItem: EncodeLike<Self::Item>,
74		I::IntoIter: ExactSizeIterator,
75	{
76		append_or_new_impl(self_encoded, iter)
77	}
78}
79
80/// Extends a SCALE-encoded vector with elements from the given `iter`.
81///
82/// `vec` must either be empty, or contain a valid SCALE-encoded `Vec<Item>` payload.
83fn append_or_new_impl<Item, I>(mut vec: Vec<u8>, iter: I) -> Result<Vec<u8>, Error>
84where
85	Item: Encode,
86	I: IntoIterator<Item = Item>,
87	I::IntoIter: ExactSizeIterator,
88{
89	let iter = iter.into_iter();
90	let items_to_append = iter.len();
91
92	if vec.is_empty() {
93		crate::codec::compact_encode_len_to(&mut vec, items_to_append)?;
94	} else {
95		let old_item_count = u32::from(Compact::<u32>::decode(&mut &vec[..])?);
96		let new_item_count = old_item_count
97			.checked_add(items_to_append as u32)
98			.ok_or("cannot append new items into a SCALE-encoded vector: length overflow due to too many items")?;
99
100		let old_item_count_encoded_bytesize = Compact::<u32>::compact_len(&old_item_count);
101		let new_item_count_encoded_bytesize = Compact::<u32>::compact_len(&new_item_count);
102
103		if old_item_count_encoded_bytesize == new_item_count_encoded_bytesize {
104			// The size of the length as encoded by SCALE didn't change, so we can just
105			// keep the old buffer as-is. We just need to update the length prefix.
106			Compact(new_item_count).using_encoded(|length_encoded| {
107				vec[..old_item_count_encoded_bytesize].copy_from_slice(length_encoded)
108			});
109		} else {
110			// We can't update the length as the new length prefix will take up more
111			// space when encoded, so we need to move our data to make space for it.
112
113			// If this overflows then it means that `vec` is bigger that half of the
114			// total address space, which means that it will be impossible to allocate
115			// enough memory for another vector of at least the same size.
116			//
117			// So let's just immediately bail with an error if this happens.
118			let new_capacity = vec.len().checked_mul(2)
119				.ok_or("cannot append new items into a SCALE-encoded vector: new vector won't fit in memory")?;
120			let mut new_vec = Vec::with_capacity(new_capacity);
121
122			crate::codec::compact_encode_len_to(&mut new_vec, new_item_count as usize)?;
123			new_vec.extend_from_slice(&vec[old_item_count_encoded_bytesize..]);
124			vec = new_vec;
125		}
126	}
127
128	// And now we just need to append the new items.
129	iter.for_each(|e| e.encode_to(&mut vec));
130	Ok(vec)
131}
132
133#[cfg(test)]
134mod tests {
135	use super::*;
136	use crate::{Encode, EncodeLike, Input};
137	use std::collections::VecDeque;
138
139	const TEST_VALUE: u32 = {
140		#[cfg(not(miri))]
141		{
142			1_000_000
143		}
144		#[cfg(miri)]
145		{
146			1_000
147		}
148	};
149
150	#[test]
151	fn vec_encode_append_works() {
152		let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
153			<Vec<u32> as EncodeAppend>::append_or_new(encoded, std::iter::once(&v)).unwrap()
154		});
155
156		let decoded = Vec::<u32>::decode(&mut &encoded[..]).unwrap();
157		assert_eq!(decoded, (0..TEST_VALUE).collect::<Vec<_>>());
158	}
159
160	#[test]
161	fn vec_encode_append_multiple_items_works() {
162		let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
163			<Vec<u32> as EncodeAppend>::append_or_new(encoded, [v, v, v, v]).unwrap()
164		});
165
166		let decoded = Vec::<u32>::decode(&mut &encoded[..]).unwrap();
167		let expected = (0..TEST_VALUE).fold(Vec::new(), |mut vec, i| {
168			vec.append(&mut vec![i, i, i, i]);
169			vec
170		});
171		assert_eq!(decoded, expected);
172	}
173
174	#[test]
175	fn vecdeque_encode_append_works() {
176		let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
177			<VecDeque<u32> as EncodeAppend>::append_or_new(encoded, std::iter::once(&v)).unwrap()
178		});
179
180		let decoded = VecDeque::<u32>::decode(&mut &encoded[..]).unwrap();
181		assert_eq!(decoded, (0..TEST_VALUE).collect::<Vec<_>>());
182	}
183
184	#[test]
185	fn vecdeque_encode_append_multiple_items_works() {
186		let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
187			<VecDeque<u32> as EncodeAppend>::append_or_new(encoded, [v, v, v, v]).unwrap()
188		});
189
190		let decoded = VecDeque::<u32>::decode(&mut &encoded[..]).unwrap();
191		let expected = (0..TEST_VALUE).fold(Vec::new(), |mut vec, i| {
192			vec.append(&mut vec![i, i, i, i]);
193			vec
194		});
195		assert_eq!(decoded, expected);
196	}
197
198	#[test]
199	fn append_non_copyable() {
200		#[derive(Eq, PartialEq, Debug)]
201		struct NoCopy {
202			data: u32,
203		}
204
205		impl EncodeLike for NoCopy {}
206
207		impl Encode for NoCopy {
208			fn encode(&self) -> Vec<u8> {
209				self.data.encode()
210			}
211		}
212
213		impl Decode for NoCopy {
214			fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
215				u32::decode(input).map(|data| Self { data })
216			}
217		}
218
219		let append = NoCopy { data: 100 };
220		let data = Vec::new();
221		let encoded =
222			<Vec<NoCopy> as EncodeAppend>::append_or_new(data, std::iter::once(&append)).unwrap();
223
224		let decoded = <Vec<NoCopy>>::decode(&mut &encoded[..]).unwrap();
225		assert_eq!(vec![append], decoded);
226	}
227
228	#[test]
229	fn vec_encode_like_append_works() {
230		let encoded = (0..TEST_VALUE).fold(Vec::new(), |encoded, v| {
231			<Vec<u32> as EncodeAppend>::append_or_new(encoded, std::iter::once(Box::new(v)))
232				.unwrap()
233		});
234
235		let decoded = Vec::<u32>::decode(&mut &encoded[..]).unwrap();
236		assert_eq!(decoded, (0..TEST_VALUE).collect::<Vec<_>>());
237	}
238}