rlp/
stream.rs

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