ethcore_bytes/
lib.rs

1// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2// This file is part of Parity.
3
4// Parity is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Parity is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Parity.  If not, see <http://www.gnu.org/licenses/>.
16
17//! General bytes-related utilities.
18//!
19//! Includes a pretty-printer for bytes, in the form of `ToPretty` and `PrettySlice`
20//! as
21
22use std::fmt;
23use std::cmp::min;
24use std::ops::{Deref, DerefMut};
25
26/// Slice pretty print helper
27pub struct PrettySlice<'a> (&'a [u8]);
28
29impl<'a> fmt::Debug for PrettySlice<'a> {
30	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
31		for i in 0..self.0.len() {
32			match i > 0 {
33				true => { write!(f, "ยท{:02x}", self.0[i])?; },
34				false => { write!(f, "{:02x}", self.0[i])?; },
35			}
36		}
37		Ok(())
38	}
39}
40
41impl<'a> fmt::Display for PrettySlice<'a> {
42	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
43		for i in 0..self.0.len() {
44			write!(f, "{:02x}", self.0[i])?;
45		}
46		Ok(())
47	}
48}
49
50/// Trait to allow a type to be pretty-printed in `format!`, where unoverridable
51/// defaults cannot otherwise be avoided.
52pub trait ToPretty {
53	/// Convert a type into a derivative form in order to make `format!` print it prettily.
54	fn pretty(&self) -> PrettySlice;
55	/// Express the object as a hex string.
56	fn to_hex(&self) -> String {
57		format!("{}", self.pretty())
58	}
59}
60
61impl<T: AsRef<[u8]>> ToPretty for T {
62	fn pretty(&self) -> PrettySlice {
63		PrettySlice(self.as_ref())
64	}
65}
66
67/// A byte collection reference that can either be a slice or a vector
68pub enum BytesRef<'a> {
69	/// This is a reference to a vector
70	Flexible(&'a mut Bytes),
71	/// This is a reference to a slice
72	Fixed(&'a mut [u8])
73}
74
75impl<'a> BytesRef<'a> {
76	/// Writes given `input` to this `BytesRef` starting at `offset`.
77	/// Returns number of bytes written to the ref.
78	/// NOTE can return number greater then `input.len()` in case flexible vector had to be extended.
79	pub fn write(&mut self, offset: usize, input: &[u8]) -> usize {
80		match *self {
81			BytesRef::Flexible(ref mut data) => {
82				let data_len = data.len();
83				let wrote = input.len() + if data_len > offset { 0 } else { offset - data_len };
84
85				data.resize(offset, 0);
86				data.extend_from_slice(input);
87				wrote
88			},
89			BytesRef::Fixed(ref mut data) if offset < data.len() => {
90				let max = min(data.len() - offset, input.len());
91				for i in 0..max {
92					data[offset + i] = input[i];
93				}
94				max
95			},
96			_ => 0
97		}
98	}
99}
100
101impl<'a> Deref for BytesRef<'a> {
102	type Target = [u8];
103
104	fn deref(&self) -> &[u8] {
105		match *self {
106			BytesRef::Flexible(ref bytes) => bytes,
107			BytesRef::Fixed(ref bytes) => bytes,
108		}
109	}
110}
111
112impl <'a> DerefMut for BytesRef<'a> {
113	fn deref_mut(&mut self) -> &mut [u8] {
114		match *self {
115			BytesRef::Flexible(ref mut bytes) => bytes,
116			BytesRef::Fixed(ref mut bytes) => bytes,
117		}
118	}
119}
120
121/// Vector of bytes.
122pub type Bytes = Vec<u8>;
123
124#[cfg(test)]
125mod tests {
126	use super::BytesRef;
127
128	#[test]
129	fn should_write_bytes_to_fixed_bytesref() {
130		// given
131		let mut data1 = vec![0, 0, 0];
132		let mut data2 = vec![0, 0, 0];
133		let (res1, res2) = {
134			let mut bytes1 = BytesRef::Fixed(&mut data1[..]);
135			let mut bytes2 = BytesRef::Fixed(&mut data2[1..2]);
136
137			// when
138			let res1 = bytes1.write(1, &[1, 1, 1]);
139			let res2 = bytes2.write(3, &[1, 1, 1]);
140			(res1, res2)
141		};
142
143		// then
144		assert_eq!(&data1, &[0, 1, 1]);
145		assert_eq!(res1, 2);
146
147		assert_eq!(&data2, &[0, 0, 0]);
148		assert_eq!(res2, 0);
149	}
150
151	#[test]
152	fn test_handles_illegal_offsets() {
153		// given
154		let mut data = vec![0, 0, 0];
155		let res = {
156			let mut bytes = BytesRef::Fixed(&mut data[..]);
157
158			// when illegal offset is provided
159			bytes.write(4, &[1])
160		};
161
162		// then no changes are made
163		assert_eq!(&data, &[0, 0, 0]);
164		assert_eq!(res, 0);
165	}
166
167	#[test]
168	fn should_write_bytes_to_flexible_bytesref() {
169		// given
170		let mut data1 = vec![0, 0, 0];
171		let mut data2 = vec![0, 0, 0];
172		let mut data3 = vec![0, 0, 0];
173		let (res1, res2, res3) = {
174			let mut bytes1 = BytesRef::Flexible(&mut data1);
175			let mut bytes2 = BytesRef::Flexible(&mut data2);
176			let mut bytes3 = BytesRef::Flexible(&mut data3);
177
178			// when
179			let res1 = bytes1.write(1, &[1, 1, 1]);
180			let res2 = bytes2.write(3, &[1, 1, 1]);
181			let res3 = bytes3.write(5, &[1, 1, 1]);
182			(res1, res2, res3)
183		};
184
185		// then
186		assert_eq!(&data1, &[0, 1, 1, 1]);
187		assert_eq!(res1, 3);
188
189		assert_eq!(&data2, &[0, 0, 0, 1, 1, 1]);
190		assert_eq!(res2, 3);
191
192		assert_eq!(&data3, &[0, 0, 0, 0, 0, 1, 1, 1]);
193		assert_eq!(res3, 5);
194	}
195}