rlp/
stream.rs

1// Copyright 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#[cfg(not(feature = "std"))]
10use alloc::vec::Vec;
11use bytes::{BufMut, BytesMut};
12use core::borrow::Borrow;
13
14use crate::traits::Encodable;
15
16#[derive(Debug, Copy, Clone)]
17struct ListInfo {
18	position: usize,
19	current: usize,
20	max: Option<usize>,
21}
22
23impl ListInfo {
24	fn new(position: usize, max: Option<usize>) -> ListInfo {
25		ListInfo { position, current: 0, max }
26	}
27}
28
29/// Appendable rlp encoder.
30pub struct RlpStream {
31	unfinished_lists: Vec<ListInfo>,
32	start_pos: usize,
33	buffer: BytesMut,
34	finished_list: bool,
35}
36
37impl Default for RlpStream {
38	fn default() -> Self {
39		RlpStream::new()
40	}
41}
42
43impl RlpStream {
44	/// Initializes instance of empty `Stream`.
45	pub fn new() -> Self {
46		Self::new_with_buffer(BytesMut::with_capacity(1024))
47	}
48
49	/// Initializes the `Stream` as a list.
50	pub fn new_list(len: usize) -> Self {
51		Self::new_list_with_buffer(BytesMut::with_capacity(1024), len)
52	}
53
54	/// Initializes instance of empty `Stream`.
55	pub fn new_with_buffer(buffer: BytesMut) -> Self {
56		RlpStream { unfinished_lists: Vec::with_capacity(16), start_pos: buffer.len(), buffer, finished_list: false }
57	}
58
59	/// Initializes the `Stream` as a list.
60	pub fn new_list_with_buffer(buffer: BytesMut, len: usize) -> Self {
61		let mut stream = RlpStream::new_with_buffer(buffer);
62		stream.begin_list(len);
63		stream
64	}
65
66	fn total_written(&self) -> usize {
67		self.buffer.len() - self.start_pos
68	}
69
70	/// Apends null to the end of stream, chainable.
71	///
72	/// ```
73	/// use rlp::RlpStream;
74	/// let mut stream = RlpStream::new_list(2);
75	/// stream.append_empty_data().append_empty_data();
76	/// let out = stream.out();
77	/// assert_eq!(out, vec![0xc2, 0x80, 0x80]);
78	/// ```
79	pub fn append_empty_data(&mut self) -> &mut Self {
80		// self push raw item
81		self.buffer.put_u8(0x80);
82
83		// try to finish and prepend the length
84		self.note_appended(1);
85
86		// return chainable self
87		self
88	}
89
90	/// Appends raw (pre-serialised) RLP data. Use with caution. Chainable.
91	pub fn append_raw(&mut self, bytes: &[u8], item_count: usize) -> &mut Self {
92		// push raw items
93		self.buffer.extend_from_slice(bytes);
94
95		// try to finish and prepend the length
96		self.note_appended(item_count);
97
98		// return chainable self
99		self
100	}
101
102	/// Appends value to the end of stream, chainable.
103	///
104	/// ```
105	/// use rlp::RlpStream;
106	/// let mut stream = RlpStream::new_list(2);
107	/// stream.append(&"cat").append(&"dog");
108	/// let out = stream.out();
109	/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
110	/// ```
111	pub fn append<E>(&mut self, value: &E) -> &mut Self
112	where
113		E: Encodable,
114	{
115		self.finished_list = false;
116		value.rlp_append(self);
117		if !self.finished_list {
118			self.note_appended(1);
119		}
120		self
121	}
122
123	/// Appends iterator to the end of stream, chainable.
124	///
125	/// ```
126	/// use rlp::RlpStream;
127	/// let mut stream = RlpStream::new_list(2);
128	/// stream.append(&"cat").append_iter("dog".as_bytes().iter().cloned());
129	/// let out = stream.out();
130	/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
131	/// ```
132	pub fn append_iter<I>(&mut self, value: I) -> &mut Self
133	where
134		I: IntoIterator<Item = u8>,
135	{
136		self.finished_list = false;
137		self.encoder().encode_iter(value);
138		if !self.finished_list {
139			self.note_appended(1);
140		}
141		self
142	}
143
144	/// Appends list of values to the end of stream, chainable.
145	pub fn append_list<E, K>(&mut self, values: &[K]) -> &mut Self
146	where
147		E: Encodable,
148		K: Borrow<E>,
149	{
150		self.begin_list(values.len());
151		for value in values {
152			self.append(value.borrow());
153		}
154		self
155	}
156
157	/// Appends value to the end of stream, but do not count it as an appended item.
158	/// It's useful for wrapper types
159	pub fn append_internal<E>(&mut self, value: &E) -> &mut Self
160	where
161		E: Encodable,
162	{
163		value.rlp_append(self);
164		self
165	}
166
167	/// Declare appending the list of given size, chainable.
168	///
169	/// ```
170	/// use rlp::RlpStream;
171	/// let mut stream = RlpStream::new_list(2);
172	/// stream.begin_list(2).append(&"cat").append(&"dog");
173	/// stream.append(&"");
174	/// let out = stream.out();
175	/// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]);
176	/// ```
177	pub fn begin_list(&mut self, len: usize) -> &mut RlpStream {
178		self.finished_list = false;
179		match len {
180			0 => {
181				// we may finish, if the appended list len is equal 0
182				self.buffer.put_u8(0xc0u8);
183				self.note_appended(1);
184				self.finished_list = true;
185			},
186			_ => {
187				// payload is longer than 1 byte only for lists > 55 bytes
188				// by pushing always this 1 byte we may avoid unnecessary shift of data
189				// both cases will need at least 1 byte header, so we push 1 byte
190				// and then, when we know the exactly size of data, the value will be updated
191				// accordingly in `insert_list_payload` method.
192				self.buffer.put_u8(0);
193
194				let position = self.total_written();
195				self.unfinished_lists.push(ListInfo::new(position, Some(len)));
196			},
197		}
198
199		// return chainable self
200		self
201	}
202
203	/// Declare appending the list of unknown size, chainable.
204	pub fn begin_unbounded_list(&mut self) -> &mut RlpStream {
205		self.finished_list = false;
206		// payload is longer than 1 byte only for lists > 55 bytes
207		// by pushing always this 1 byte we may avoid unnecessary shift of data
208		self.buffer.put_u8(0);
209		let position = self.total_written();
210		self.unfinished_lists.push(ListInfo::new(position, None));
211		// return chainable self
212		self
213	}
214
215	/// Appends raw (pre-serialised) RLP data. Checks for size overflow.
216	pub fn append_raw_checked(&mut self, bytes: &[u8], item_count: usize, max_size: usize) -> bool {
217		if self.estimate_size(bytes.len()) > max_size {
218			return false
219		}
220		self.append_raw(bytes, item_count);
221		true
222	}
223
224	/// Calculate total RLP size for appended payload.
225	pub fn estimate_size(&self, add: usize) -> usize {
226		let total_size = self.total_written() + add;
227		let mut base_size = total_size;
228		for list in &self.unfinished_lists[..] {
229			let len = total_size - list.position;
230			if len > 55 {
231				let leading_empty_bytes = (len as u64).leading_zeros() as usize / 8;
232				let size_bytes = 8 - leading_empty_bytes;
233				base_size += size_bytes;
234			}
235		}
236		base_size
237	}
238
239	/// Returns current RLP size in bytes for the data pushed into the list.
240	pub fn len(&self) -> usize {
241		self.estimate_size(0)
242	}
243
244	pub fn is_empty(&self) -> bool {
245		self.len() == 0
246	}
247
248	/// Clear the output stream so far.
249	///
250	/// ```
251	/// use rlp::RlpStream;
252	/// let mut stream = RlpStream::new_list(3);
253	/// stream.append(&"cat");
254	/// stream.clear();
255	/// stream.append(&"dog");
256	/// let out = stream.out();
257	/// assert_eq!(out, vec![0x83, b'd', b'o', b'g']);
258	/// ```
259	pub fn clear(&mut self) {
260		// clear bytes
261		self.buffer.truncate(self.start_pos);
262
263		// clear lists
264		self.unfinished_lists.clear();
265	}
266
267	/// Returns true if stream doesnt expect any more items.
268	///
269	/// ```
270	/// use rlp::RlpStream;
271	/// let mut stream = RlpStream::new_list(2);
272	/// stream.append(&"cat");
273	/// assert_eq!(stream.is_finished(), false);
274	/// stream.append(&"dog");
275	/// assert_eq!(stream.is_finished(), true);
276	/// let out = stream.out();
277	/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']);
278	/// ```
279	pub fn is_finished(&self) -> bool {
280		self.unfinished_lists.is_empty()
281	}
282
283	/// Get raw encoded bytes
284	pub fn as_raw(&self) -> &[u8] {
285		//&self.encoder.bytes
286		&self.buffer
287	}
288
289	/// Streams out encoded bytes.
290	///
291	/// panic! if stream is not finished.
292	pub fn out(self) -> BytesMut {
293		if self.is_finished() {
294			self.buffer
295		} else {
296			panic!()
297		}
298	}
299
300	/// Try to finish lists
301	fn note_appended(&mut self, inserted_items: usize) {
302		if self.unfinished_lists.is_empty() {
303			return
304		}
305
306		let back = self.unfinished_lists.len() - 1;
307		let should_finish = match self.unfinished_lists.get_mut(back) {
308			None => false,
309			Some(ref mut x) => {
310				x.current += inserted_items;
311				match x.max {
312					Some(ref max) if x.current > *max => panic!("You cannot append more items than you expect!"),
313					Some(ref max) => x.current == *max,
314					_ => false,
315				}
316			},
317		};
318		if should_finish {
319			let x = self.unfinished_lists.pop().unwrap();
320			let len = self.total_written() - x.position;
321			self.encoder().insert_list_payload(len, x.position);
322			self.note_appended(1);
323		}
324		self.finished_list = should_finish;
325	}
326
327	pub fn encoder(&mut self) -> BasicEncoder {
328		BasicEncoder::new(self, self.start_pos)
329	}
330
331	/// Finalize current unbounded list. Panics if no unbounded list has been opened.
332	pub fn finalize_unbounded_list(&mut self) {
333		let list = self.unfinished_lists.pop().expect("No open list.");
334		if list.max.is_some() {
335			panic!("List type mismatch.");
336		}
337		let len = self.total_written() - list.position;
338		self.encoder().insert_list_payload(len, list.position);
339		self.note_appended(1);
340		self.finished_list = true;
341	}
342}
343
344pub struct BasicEncoder<'a> {
345	buffer: &'a mut BytesMut,
346	start_pos: usize,
347}
348
349impl<'a> BasicEncoder<'a> {
350	fn new(stream: &'a mut RlpStream, start_pos: usize) -> Self {
351		BasicEncoder { buffer: &mut stream.buffer, start_pos }
352	}
353
354	fn total_written(&self) -> usize {
355		self.buffer.len() - self.start_pos
356	}
357
358	fn insert_size(&mut self, size: usize, position: usize) -> u8 {
359		let size = size as u32;
360		let leading_empty_bytes = size.leading_zeros() as usize / 8;
361		let size_bytes = 4 - leading_empty_bytes as u8;
362		let buffer: [u8; 4] = size.to_be_bytes();
363		assert!(position <= self.total_written());
364
365		self.buffer.extend_from_slice(&buffer[leading_empty_bytes..]);
366		self.buffer[self.start_pos + position..].rotate_right(size_bytes as usize);
367		size_bytes as u8
368	}
369
370	/// Inserts list prefix at given position
371	fn insert_list_payload(&mut self, len: usize, pos: usize) {
372		// 1 byte was already reserved for payload earlier
373		match len {
374			0..=55 => {
375				self.buffer[self.start_pos + pos - 1] = 0xc0u8 + len as u8;
376			},
377			_ => {
378				let inserted_bytes = self.insert_size(len, pos);
379				self.buffer[self.start_pos + pos - 1] = 0xf7u8 + inserted_bytes;
380			},
381		};
382	}
383
384	pub fn encode_value(&mut self, value: &[u8]) {
385		self.encode_iter(value.iter().cloned());
386	}
387
388	/// Pushes encoded value to the end of buffer
389	pub fn encode_iter<I>(&mut self, value: I)
390	where
391		I: IntoIterator<Item = u8>,
392	{
393		let mut value = value.into_iter();
394		let len = match value.size_hint() {
395			(lower, Some(upper)) if lower == upper => lower,
396			_ => {
397				let value = value.collect::<Vec<_>>();
398				return self.encode_iter(value)
399			},
400		};
401		match len {
402			// just 0
403			0 => self.buffer.put_u8(0x80u8),
404			len @ 1..=55 => {
405				let first = value.next().expect("iterator length is higher than 1");
406				if len == 1 && first < 0x80 {
407					// byte is its own encoding if < 0x80
408					self.buffer.put_u8(first);
409				} else {
410					// (prefix + length), followed by the string
411					self.buffer.put_u8(0x80u8 + len as u8);
412					self.buffer.put_u8(first);
413					self.buffer.extend(value);
414				}
415			},
416			// (prefix + length of length), followed by the length, followd by the string
417			len => {
418				self.buffer.put_u8(0);
419				let position = self.total_written();
420				let inserted_bytes = self.insert_size(len, position);
421				self.buffer[self.start_pos + position - 1] = 0xb7 + inserted_bytes;
422				self.buffer.extend(value);
423			},
424		}
425	}
426}