openethereum/util/src/bytes.rs

244 lines
6.2 KiB
Rust

// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Unified interfaces for bytes operations on basic types
//!
//! # Examples
//! ```rust
//! extern crate ethcore_util as util;
//!
//! fn bytes_convertable() {
//! use util::bytes::BytesConvertable;
//!
//! let arr = [0; 5];
//! let slice: &[u8] = arr.as_slice();
//! }
//!
//! fn main() {
//! bytes_convertable();
//! }
//! ```
use std::fmt;
use std::slice;
use std::ops::{Deref, DerefMut};
/// Slice pretty print helper
pub struct PrettySlice<'a> (&'a [u8]);
impl<'a> fmt::Debug for PrettySlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.0.len() {
match i > 0 {
true => { try!(write!(f, "·{:02x}", self.0[i])); },
false => { try!(write!(f, "{:02x}", self.0[i])); },
}
}
Ok(())
}
}
impl<'a> fmt::Display for PrettySlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.0.len() {
try!(write!(f, "{:02x}", self.0[i]));
}
Ok(())
}
}
/// Trait to allow a type to be pretty-printed in `format!`, where unoverridable
/// defaults cannot otherwise be avoided.
pub trait ToPretty {
/// Convert a type into a derivative form in order to make `format!` print it prettily.
fn pretty(&self) -> PrettySlice;
/// Express the object as a hex string.
fn to_hex(&self) -> String {
format!("{}", self.pretty())
}
}
impl<'a> ToPretty for &'a [u8] {
fn pretty(&self) -> PrettySlice {
PrettySlice(self)
}
}
impl<'a> ToPretty for &'a Bytes {
fn pretty(&self) -> PrettySlice {
PrettySlice(self.as_slice())
}
}
impl ToPretty for Bytes {
fn pretty(&self) -> PrettySlice {
PrettySlice(self.as_slice())
}
}
/// A byte collection reference that can either be a slice or a vector
pub enum BytesRef<'a> {
/// This is a reference to a vector
Flexible(&'a mut Bytes),
/// This is a reference to a slice
Fixed(&'a mut [u8])
}
impl<'a> Deref for BytesRef<'a> {
type Target = [u8];
fn deref(&self) -> &[u8] {
match *self {
BytesRef::Flexible(ref bytes) => bytes,
BytesRef::Fixed(ref bytes) => bytes,
}
}
}
impl <'a> DerefMut for BytesRef<'a> {
fn deref_mut(&mut self) -> &mut [u8] {
match *self {
BytesRef::Flexible(ref mut bytes) => bytes,
BytesRef::Fixed(ref mut bytes) => bytes,
}
}
}
/// Vector of bytes
pub type Bytes = Vec<u8>;
/// Slice of bytes to underlying memory
pub trait BytesConvertable {
/// Get the underlying byte-wise representation of the value.
fn as_slice(&self) -> &[u8];
/// Get a copy of the underlying byte-wise representation.
fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() }
}
impl<T> BytesConvertable for T where T: AsRef<[u8]> {
fn as_slice(&self) -> &[u8] { self.as_ref() }
}
#[test]
fn bytes_convertable() {
assert_eq!(vec![0x12u8, 0x34].as_slice(), &[0x12u8, 0x34]);
assert!([0u8; 0].as_slice().is_empty());
}
/// Simple trait to allow for raw population of a Sized object from a byte slice.
pub trait Populatable {
/// Copies a bunch of bytes `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, zero-out the remaining bytes.
fn populate_raw(&mut self, d: &[u8]) {
let mut s = self.as_slice_mut();
for i in 0..s.len() {
s[i] = if i < d.len() {d[i]} else {0};
}
}
/// Copies a bunch of bytes `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, will leave some bytes untouched.
fn copy_raw(&mut self, d: &[u8]) {
use std::io::Write;
self.as_slice_mut().write(d).unwrap();
}
/// Copies the raw representation of an object `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, zero-out the remaining bytes.
fn populate_raw_from(&mut self, d: &BytesConvertable) { self.populate_raw(d.as_slice()); }
/// Copies the raw representation of an object `d` to `self`, overwriting as necessary.
///
/// If `d` is smaller, will leave some bytes untouched.
fn copy_raw_from(&mut self, d: &BytesConvertable) { self.copy_raw(d.as_slice()); }
/// Get the raw slice for this object.
fn as_slice_mut(&mut self) -> &mut [u8];
}
impl<T> Populatable for T where T: Sized {
fn as_slice_mut(&mut self) -> &mut [u8] {
use std::mem;
unsafe {
slice::from_raw_parts_mut(self as *mut T as *mut u8, mem::size_of::<T>())
}
}
}
impl<T> Populatable for [T] where T: Sized {
fn as_slice_mut(&mut self) -> &mut [u8] {
use std::mem;
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr() as *mut u8, mem::size_of::<T>() * self.len())
}
}
}
#[test]
fn fax_raw() {
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 2][..]);
assert_eq!(x, [1u8, 1, 255, 255]);
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 6][..]);
assert_eq!(x, [1u8, 1, 1, 1]);
}
#[test]
fn populate_raw() {
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 2][..]);
assert_eq!(x, [1u8, 1, 0, 0]);
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 6][..]);
assert_eq!(x, [1u8, 1, 1, 1]);
}
#[test]
fn populate_raw_dyn() {
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 2][..]);
assert_eq!(&x[..], [1u8, 1, 0, 0]);
let mut x = [255u8; 4];
x.populate_raw(&[1u8; 6][..]);
assert_eq!(&x[..], [1u8, 1, 1, 1]);
}
#[test]
fn fax_raw_dyn() {
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 2][..]);
assert_eq!(&x[..], [1u8, 1, 255, 255]);
let mut x = [255u8; 4];
x.copy_raw(&[1u8; 6][..]);
assert_eq!(&x[..], [1u8, 1, 1, 1]);
}
#[test]
fn populate_big_types() {
use hash::*;
let a: H160 = "ffffffffffffffffffffffffffffffffffffffff".into();
let mut h: H256 = 0x69.into();
h.populate_raw_from(&a);
assert_eq!(h, "ffffffffffffffffffffffffffffffffffffffff000000000000000000000000".into());
let mut h: H256 = 0x69.into();
h.copy_raw_from(&a);
assert_eq!(h, "ffffffffffffffffffffffffffffffffffffffff000000000000000000000069".into());
}