Bug 1175322 - Import byteorder crate. r=k17e

This is the source of Andrew Gallant's byteorder crate,
used end the MIT license.

It has been slightly modified to re-export the new sub-module
so it can be built as a mod inside our MP4Metadata crate since
we don't currently support crate dependencies.
This commit is contained in:
Ralph Giles 2015-06-16 15:51:00 -07:00
parent 35b5a70f29
commit dbec6e99b1
3 changed files with 996 additions and 1 deletions

View File

@ -41,7 +41,7 @@ pub struct TrackHeaderBox {
pub height: u32,
}
extern crate byteorder;
mod byteorder;
use byteorder::{BigEndian, ReadBytesExt};
use std::io::{Read, Result, Seek, SeekFrom, Take};
use std::io::Cursor;

View File

@ -0,0 +1,698 @@
/*!
This crate provides convenience methods for encoding and decoding numbers
in either big-endian or little-endian order.
The organization of the crate is pretty simple. A trait, `ByteOrder`, specifies
byte conversion methods for each type of number in Rust (sans numbers that have
a platform dependent size like `usize` and `isize`). Two types, `BigEndian`
and `LittleEndian` implement these methods. Finally, `ReadBytesExt` and
`WriteBytesExt` provide convenience methods available to all types that
implement `Read` and `Write`.
# Examples
Read unsigned 16 bit big-endian integers from a `Read` type:
```rust
use std::io::Cursor;
use byteorder::{BigEndian, ReadBytesExt};
let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
// Note that we use type parameters to indicate which kind of byte order
// we want!
assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());
assert_eq!(768, rdr.read_u16::<BigEndian>().unwrap());
```
Write unsigned 16 bit little-endian integers to a `Write` type:
```rust
use byteorder::{LittleEndian, WriteBytesExt};
let mut wtr = vec![];
wtr.write_u16::<LittleEndian>(517).unwrap();
wtr.write_u16::<LittleEndian>(768).unwrap();
assert_eq!(wtr, vec![5, 2, 0, 3]);
```
*/
#![crate_name = "byteorder"]
#![doc(html_root_url = "http://burntsushi.net/rustdoc/byteorder")]
#![deny(missing_docs)]
use std::mem::transmute;
pub use byteorder::new::{ReadBytesExt, WriteBytesExt, Error, Result};
// Re-export new so gecko and build us as a mod intead of a crate.
pub mod new;
fn extend_sign(val: u64, nbytes: usize) -> i64 {
let shift = (8 - nbytes) * 8;
(val << shift) as i64 >> shift
}
/// ByteOrder describes types that can serialize integers as bytes.
///
/// Note that `Self` does not appear anywhere in this trait's definition!
/// Therefore, in order to use it, you'll need to use syntax like
/// `T::read_u16(&[0, 1])` where `T` implements `ByteOrder`.
///
/// This crate provides two types that implement `ByteOrder`: `BigEndian`
/// and `LittleEndian`.
///
/// # Examples
///
/// Write and read `u32` numbers in little endian order:
///
/// ```rust
/// use byteorder::{ByteOrder, LittleEndian};
///
/// let mut buf = [0; 4];
/// LittleEndian::write_u32(&mut buf, 1_000_000);
/// assert_eq!(1_000_000, LittleEndian::read_u32(&buf));
/// ```
///
/// Write and read `i16` numbers in big endian order:
///
/// ```rust
/// use byteorder::{ByteOrder, BigEndian};
///
/// let mut buf = [0; 2];
/// BigEndian::write_i16(&mut buf, -50_000);
/// assert_eq!(-50_000, BigEndian::read_i16(&buf));
/// ```
pub trait ByteOrder {
/// Reads an unsigned 16 bit integer from `buf`.
///
/// Panics when `buf.len() < 2`.
fn read_u16(buf: &[u8]) -> u16;
/// Reads an unsigned 32 bit integer from `buf`.
///
/// Panics when `buf.len() < 4`.
fn read_u32(buf: &[u8]) -> u32;
/// Reads an unsigned 64 bit integer from `buf`.
///
/// Panics when `buf.len() < 8`.
fn read_u64(buf: &[u8]) -> u64;
/// Reads an unsigned n-bytes integer from `buf`.
///
/// Panics when `nbytes < 1` or `nbytes > 8` or
/// `buf.len() < nbytes`
fn read_uint(buf: &[u8], nbytes: usize) -> u64;
/// Writes an unsigned 16 bit integer `n` to `buf`.
///
/// Panics when `buf.len() < 2`.
fn write_u16(buf: &mut [u8], n: u16);
/// Writes an unsigned 32 bit integer `n` to `buf`.
///
/// Panics when `buf.len() < 4`.
fn write_u32(buf: &mut [u8], n: u32);
/// Writes an unsigned 64 bit integer `n` to `buf`.
///
/// Panics when `buf.len() < 8`.
fn write_u64(buf: &mut [u8], n: u64);
/// Reads a signed 16 bit integer from `buf`.
///
/// Panics when `buf.len() < 2`.
fn read_i16(buf: &[u8]) -> i16 {
Self::read_u16(buf) as i16
}
/// Reads a signed 32 bit integer from `buf`.
///
/// Panics when `buf.len() < 4`.
fn read_i32(buf: &[u8]) -> i32 {
Self::read_u32(buf) as i32
}
/// Reads a signed 64 bit integer from `buf`.
///
/// Panics when `buf.len() < 8`.
fn read_i64(buf: &[u8]) -> i64 {
Self::read_u64(buf) as i64
}
/// Reads a signed n-bytes integer from `buf`.
///
/// Panics when `nbytes < 1` or `nbytes > 8` or
/// `buf.len() < nbytes`
fn read_int(buf: &[u8], nbytes: usize) -> i64 {
extend_sign(Self::read_uint(buf, nbytes), nbytes)
}
/// Reads a IEEE754 single-precision (4 bytes) floating point number.
///
/// Panics when `buf.len() < 4`.
fn read_f32(buf: &[u8]) -> f32 {
unsafe { transmute(Self::read_u32(buf)) }
}
/// Reads a IEEE754 double-precision (8 bytes) floating point number.
///
/// Panics when `buf.len() < 8`.
fn read_f64(buf: &[u8]) -> f64 {
unsafe { transmute(Self::read_u64(buf)) }
}
/// Writes a signed 16 bit integer `n` to `buf`.
///
/// Panics when `buf.len() < 2`.
fn write_i16(buf: &mut [u8], n: i16) {
Self::write_u16(buf, n as u16)
}
/// Writes a signed 32 bit integer `n` to `buf`.
///
/// Panics when `buf.len() < 4`.
fn write_i32(buf: &mut [u8], n: i32) {
Self::write_u32(buf, n as u32)
}
/// Writes a signed 64 bit integer `n` to `buf`.
///
/// Panics when `buf.len() < 8`.
fn write_i64(buf: &mut [u8], n: i64) {
Self::write_u64(buf, n as u64)
}
/// Writes a IEEE754 single-precision (4 bytes) floating point number.
///
/// Panics when `buf.len() < 4`.
fn write_f32(buf: &mut [u8], n: f32) {
Self::write_u32(buf, unsafe { transmute(n) })
}
/// Writes a IEEE754 double-precision (8 bytes) floating point number.
///
/// Panics when `buf.len() < 8`.
fn write_f64(buf: &mut [u8], n: f64) {
Self::write_u64(buf, unsafe { transmute(n) })
}
}
/// Defines big-endian serialization.
///
/// Note that this type has no value constructor. It is used purely at the
/// type level.
#[allow(missing_copy_implementations)] pub enum BigEndian {}
/// Defines little-endian serialization.
///
/// Note that this type has no value constructor. It is used purely at the
/// type level.
#[allow(missing_copy_implementations)] pub enum LittleEndian {}
/// Defines system native-endian serialization.
///
/// Note that this type has no value constructor. It is used purely at the
/// type level.
#[cfg(target_endian = "little")]
pub type NativeEndian = LittleEndian;
/// Defines system native-endian serialization.
///
/// Note that this type has no value constructor. It is used purely at the
/// type level.
#[cfg(target_endian = "big")]
pub type NativeEndian = BigEndian;
macro_rules! read_num_bytes {
($ty:ty, $size:expr, $src:expr, $which:ident) => ({
assert!($src.len() >= $size); // critical for memory safety!
unsafe {
(*($src.as_ptr() as *const $ty)).$which()
}
});
($ty:ty, $size:expr, le $bytes:expr, $src:expr, $which:ident) => ({
use std::ptr::copy_nonoverlapping;
assert!($bytes > 0 && $bytes < 9 && $bytes <= $src.len());
let mut out = [0u8; $size];
let ptr_out = out.as_mut_ptr();
unsafe {
copy_nonoverlapping($src.as_ptr(), ptr_out, $bytes);
(*(ptr_out as *const $ty)).$which()
}
});
($ty:ty, $size:expr, be $bytes:expr, $src:expr, $which:ident) => ({
use std::ptr::copy_nonoverlapping;
assert!($bytes > 0 && $bytes < 9 && $bytes <= $src.len());
let mut out = [0u8; $size];
let ptr_out = out.as_mut_ptr();
unsafe {
copy_nonoverlapping($src.as_ptr(),
ptr_out.offset((8 - $bytes) as isize), $bytes);
(*(ptr_out as *const $ty)).$which()
}
});
}
macro_rules! write_num_bytes {
($ty:ty, $size:expr, $n:expr, $dst:expr, $which:ident) => ({
use std::ptr::copy_nonoverlapping;
assert!($dst.len() >= $size); // critical for memory safety!
unsafe {
// N.B. https://github.com/rust-lang/rust/issues/22776
let bytes = transmute::<_, [u8; $size]>($n.$which());
copy_nonoverlapping((&bytes).as_ptr(), $dst.as_mut_ptr(), $size);
}
});
}
impl ByteOrder for BigEndian {
fn read_u16(buf: &[u8]) -> u16 {
read_num_bytes!(u16, 2, buf, to_be)
}
fn read_u32(buf: &[u8]) -> u32 {
read_num_bytes!(u32, 4, buf, to_be)
}
fn read_u64(buf: &[u8]) -> u64 {
read_num_bytes!(u64, 8, buf, to_be)
}
fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
read_num_bytes!(u64, 8, be nbytes, buf, to_be)
}
fn write_u16(buf: &mut [u8], n: u16) {
write_num_bytes!(u16, 2, n, buf, to_be);
}
fn write_u32(buf: &mut [u8], n: u32) {
write_num_bytes!(u32, 4, n, buf, to_be);
}
fn write_u64(buf: &mut [u8], n: u64) {
write_num_bytes!(u64, 8, n, buf, to_be);
}
}
impl ByteOrder for LittleEndian {
fn read_u16(buf: &[u8]) -> u16 {
read_num_bytes!(u16, 2, buf, to_le)
}
fn read_u32(buf: &[u8]) -> u32 {
read_num_bytes!(u32, 4, buf, to_le)
}
fn read_u64(buf: &[u8]) -> u64 {
read_num_bytes!(u64, 8, buf, to_le)
}
fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
read_num_bytes!(u64, 8, le nbytes, buf, to_le)
}
fn write_u16(buf: &mut [u8], n: u16) {
write_num_bytes!(u16, 2, n, buf, to_le);
}
fn write_u32(buf: &mut [u8], n: u32) {
write_num_bytes!(u32, 4, n, buf, to_le);
}
fn write_u64(buf: &mut [u8], n: u64) {
write_num_bytes!(u64, 8, n, buf, to_le);
}
}
#[cfg(test)]
mod test {
extern crate quickcheck;
extern crate rand;
use test::rand::thread_rng;
use test::quickcheck::{QuickCheck, StdGen, Testable};
const U64_MAX: u64 = ::std::u64::MAX;
const I64_MAX: u64 = ::std::i64::MAX as u64;
fn qc_sized<A: Testable>(f: A, size: u64) {
QuickCheck::new()
.gen(StdGen::new(thread_rng(), size as usize))
.tests(1_00)
.max_tests(10_000)
.quickcheck(f);
}
macro_rules! qc_byte_order {
($name:ident, $ty_int:ident, $max:expr,
$bytes:expr, $read:ident, $write:ident) => (
mod $name {
use {BigEndian, ByteOrder, NativeEndian, LittleEndian};
use super::qc_sized;
#[test]
fn big_endian() {
let max = ($max - 1) >> (8 * (8 - $bytes));
fn prop(n: $ty_int) -> bool {
let mut buf = [0; 8];
BigEndian::$write(&mut buf, n);
n == BigEndian::$read(&mut buf[8 - $bytes..], $bytes)
}
qc_sized(prop as fn($ty_int) -> bool, max);
}
#[test]
fn little_endian() {
let max = ($max - 1) >> (8 * (8 - $bytes));
fn prop(n: $ty_int) -> bool {
let mut buf = [0; 8];
LittleEndian::$write(&mut buf, n);
n == LittleEndian::$read(&mut buf[..$bytes], $bytes)
}
qc_sized(prop as fn($ty_int) -> bool, max);
}
#[test]
fn native_endian() {
let max = ($max - 1) >> (8 * (8 - $bytes));
fn prop(n: $ty_int) -> bool {
let mut buf = [0; 8];
NativeEndian::$write(&mut buf, n);
n == NativeEndian::$read(&mut buf[..$bytes], $bytes)
}
qc_sized(prop as fn($ty_int) -> bool, max);
}
}
);
($name:ident, $ty_int:ident, $max:expr,
$read:ident, $write:ident) => (
mod $name {
use std::mem::size_of;
use {BigEndian, ByteOrder, NativeEndian, LittleEndian};
use super::qc_sized;
#[test]
fn big_endian() {
fn prop(n: $ty_int) -> bool {
let bytes = size_of::<$ty_int>();
let mut buf = [0; 8];
BigEndian::$write(&mut buf[8 - bytes..], n);
n == BigEndian::$read(&mut buf[8 - bytes..])
}
qc_sized(prop as fn($ty_int) -> bool, $max - 1);
}
#[test]
fn little_endian() {
fn prop(n: $ty_int) -> bool {
let bytes = size_of::<$ty_int>();
let mut buf = [0; 8];
LittleEndian::$write(&mut buf[..bytes], n);
n == LittleEndian::$read(&mut buf[..bytes])
}
qc_sized(prop as fn($ty_int) -> bool, $max - 1);
}
#[test]
fn native_endian() {
fn prop(n: $ty_int) -> bool {
let bytes = size_of::<$ty_int>();
let mut buf = [0; 8];
NativeEndian::$write(&mut buf[..bytes], n);
n == NativeEndian::$read(&mut buf[..bytes])
}
qc_sized(prop as fn($ty_int) -> bool, $max - 1);
}
}
);
}
qc_byte_order!(prop_u16, u16, ::std::u16::MAX as u64, read_u16, write_u16);
qc_byte_order!(prop_i16, i16, ::std::i16::MAX as u64, read_i16, write_i16);
qc_byte_order!(prop_u32, u32, ::std::u32::MAX as u64, read_u32, write_u32);
qc_byte_order!(prop_i32, i32, ::std::i32::MAX as u64, read_i32, write_i32);
qc_byte_order!(prop_u64, u64, ::std::u64::MAX as u64, read_u64, write_u64);
qc_byte_order!(prop_i64, i64, ::std::i64::MAX as u64, read_i64, write_i64);
qc_byte_order!(prop_f32, f32, ::std::u64::MAX as u64, read_f32, write_f32);
qc_byte_order!(prop_f64, f64, ::std::i64::MAX as u64, read_f64, write_f64);
qc_byte_order!(prop_uint_1, u64, super::U64_MAX, 1, read_uint, write_u64);
qc_byte_order!(prop_uint_2, u64, super::U64_MAX, 2, read_uint, write_u64);
qc_byte_order!(prop_uint_3, u64, super::U64_MAX, 3, read_uint, write_u64);
qc_byte_order!(prop_uint_4, u64, super::U64_MAX, 4, read_uint, write_u64);
qc_byte_order!(prop_uint_5, u64, super::U64_MAX, 5, read_uint, write_u64);
qc_byte_order!(prop_uint_6, u64, super::U64_MAX, 6, read_uint, write_u64);
qc_byte_order!(prop_uint_7, u64, super::U64_MAX, 7, read_uint, write_u64);
qc_byte_order!(prop_uint_8, u64, super::U64_MAX, 8, read_uint, write_u64);
qc_byte_order!(prop_int_1, i64, super::I64_MAX, 1, read_int, write_i64);
qc_byte_order!(prop_int_2, i64, super::I64_MAX, 2, read_int, write_i64);
qc_byte_order!(prop_int_3, i64, super::I64_MAX, 3, read_int, write_i64);
qc_byte_order!(prop_int_4, i64, super::I64_MAX, 4, read_int, write_i64);
qc_byte_order!(prop_int_5, i64, super::I64_MAX, 5, read_int, write_i64);
qc_byte_order!(prop_int_6, i64, super::I64_MAX, 6, read_int, write_i64);
qc_byte_order!(prop_int_7, i64, super::I64_MAX, 7, read_int, write_i64);
qc_byte_order!(prop_int_8, i64, super::I64_MAX, 8, read_int, write_i64);
macro_rules! qc_bytes_ext {
($name:ident, $ty_int:ident, $max:expr,
$bytes:expr, $read:ident, $write:ident) => (
mod $name {
use std::io::Cursor;
use {
ReadBytesExt, WriteBytesExt,
BigEndian, NativeEndian, LittleEndian,
};
use super::qc_sized;
#[test]
fn big_endian() {
let max = ($max - 1) >> (8 * (8 - $bytes));
fn prop(n: $ty_int) -> bool {
let mut wtr = vec![];
wtr.$write::<BigEndian>(n).unwrap();
let mut rdr = Vec::new();
rdr.extend(wtr[8 - $bytes..].iter().map(|&x|x));
let mut rdr = Cursor::new(rdr);
n == rdr.$read::<BigEndian>($bytes).unwrap()
}
qc_sized(prop as fn($ty_int) -> bool, max);
}
#[test]
fn little_endian() {
let max = ($max - 1) >> (8 * (8 - $bytes));
fn prop(n: $ty_int) -> bool {
let mut wtr = vec![];
wtr.$write::<LittleEndian>(n).unwrap();
let mut rdr = Cursor::new(wtr);
n == rdr.$read::<LittleEndian>($bytes).unwrap()
}
qc_sized(prop as fn($ty_int) -> bool, max);
}
#[test]
fn native_endian() {
let max = ($max - 1) >> (8 * (8 - $bytes));
fn prop(n: $ty_int) -> bool {
let mut wtr = vec![];
wtr.$write::<NativeEndian>(n).unwrap();
let mut rdr = Cursor::new(wtr);
n == rdr.$read::<NativeEndian>($bytes).unwrap()
}
qc_sized(prop as fn($ty_int) -> bool, max);
}
}
);
($name:ident, $ty_int:ident, $max:expr, $read:ident, $write:ident) => (
mod $name {
use std::io::Cursor;
use {
ReadBytesExt, WriteBytesExt,
BigEndian, NativeEndian, LittleEndian,
};
use super::qc_sized;
#[test]
fn big_endian() {
fn prop(n: $ty_int) -> bool {
let mut wtr = vec![];
wtr.$write::<BigEndian>(n).unwrap();
let mut rdr = Cursor::new(wtr);
n == rdr.$read::<BigEndian>().unwrap()
}
qc_sized(prop as fn($ty_int) -> bool, $max - 1);
}
#[test]
fn little_endian() {
fn prop(n: $ty_int) -> bool {
let mut wtr = vec![];
wtr.$write::<LittleEndian>(n).unwrap();
let mut rdr = Cursor::new(wtr);
n == rdr.$read::<LittleEndian>().unwrap()
}
qc_sized(prop as fn($ty_int) -> bool, $max - 1);
}
#[test]
fn native_endian() {
fn prop(n: $ty_int) -> bool {
let mut wtr = vec![];
wtr.$write::<NativeEndian>(n).unwrap();
let mut rdr = Cursor::new(wtr);
n == rdr.$read::<NativeEndian>().unwrap()
}
qc_sized(prop as fn($ty_int) -> bool, $max - 1);
}
}
);
}
qc_bytes_ext!(prop_ext_u16, u16, ::std::u16::MAX as u64, read_u16, write_u16);
qc_bytes_ext!(prop_ext_i16, i16, ::std::i16::MAX as u64, read_i16, write_i16);
qc_bytes_ext!(prop_ext_u32, u32, ::std::u32::MAX as u64, read_u32, write_u32);
qc_bytes_ext!(prop_ext_i32, i32, ::std::i32::MAX as u64, read_i32, write_i32);
qc_bytes_ext!(prop_ext_u64, u64, ::std::u64::MAX as u64, read_u64, write_u64);
qc_bytes_ext!(prop_ext_i64, i64, ::std::i64::MAX as u64, read_i64, write_i64);
qc_bytes_ext!(prop_ext_f32, f32, ::std::u64::MAX as u64, read_f32, write_f32);
qc_bytes_ext!(prop_ext_f64, f64, ::std::i64::MAX as u64, read_f64, write_f64);
qc_bytes_ext!(prop_ext_uint_1, u64, super::U64_MAX, 1, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_2, u64, super::U64_MAX, 2, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_3, u64, super::U64_MAX, 3, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_4, u64, super::U64_MAX, 4, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_5, u64, super::U64_MAX, 5, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_6, u64, super::U64_MAX, 6, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_7, u64, super::U64_MAX, 7, read_uint, write_u64);
qc_bytes_ext!(prop_ext_uint_8, u64, super::U64_MAX, 8, read_uint, write_u64);
qc_bytes_ext!(prop_ext_int_1, i64, super::I64_MAX, 1, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_2, i64, super::I64_MAX, 2, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_3, i64, super::I64_MAX, 3, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_4, i64, super::I64_MAX, 4, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_5, i64, super::I64_MAX, 5, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_6, i64, super::I64_MAX, 6, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_7, i64, super::I64_MAX, 7, read_int, write_i64);
qc_bytes_ext!(prop_ext_int_8, i64, super::I64_MAX, 8, read_int, write_i64);
// Test that all of the byte conversion functions panic when given a
// buffer that is too small.
//
// These tests are critical to ensure safety, otherwise we might end up
// with a buffer overflow.
macro_rules! too_small {
($name:ident, $maximally_small:expr, $zero:expr,
$read:ident, $write:ident) => (
mod $name {
use {BigEndian, ByteOrder, NativeEndian, LittleEndian};
#[test]
#[should_panic]
fn read_big_endian() {
let buf = [0; $maximally_small];
BigEndian::$read(&buf);
}
#[test]
#[should_panic]
fn read_little_endian() {
let buf = [0; $maximally_small];
LittleEndian::$read(&buf);
}
#[test]
#[should_panic]
fn read_native_endian() {
let buf = [0; $maximally_small];
NativeEndian::$read(&buf);
}
#[test]
#[should_panic]
fn write_big_endian() {
let mut buf = [0; $maximally_small];
BigEndian::$write(&mut buf, $zero);
}
#[test]
#[should_panic]
fn write_little_endian() {
let mut buf = [0; $maximally_small];
LittleEndian::$write(&mut buf, $zero);
}
#[test]
#[should_panic]
fn write_native_endian() {
let mut buf = [0; $maximally_small];
NativeEndian::$write(&mut buf, $zero);
}
}
);
($name:ident, $maximally_small:expr, $read:ident) => (
mod $name {
use {BigEndian, ByteOrder, NativeEndian, LittleEndian};
#[test]
#[should_panic]
fn read_big_endian() {
let buf = [0; $maximally_small];
BigEndian::$read(&buf, $maximally_small + 1);
}
#[test]
#[should_panic]
fn read_little_endian() {
let buf = [0; $maximally_small];
LittleEndian::$read(&buf, $maximally_small + 1);
}
#[test]
#[should_panic]
fn read_native_endian() {
let buf = [0; $maximally_small];
NativeEndian::$read(&buf, $maximally_small + 1);
}
}
);
}
too_small!(small_u16, 1, 0, read_u16, write_u16);
too_small!(small_i16, 1, 0, read_i16, write_i16);
too_small!(small_u32, 3, 0, read_u32, write_u32);
too_small!(small_i32, 3, 0, read_i32, write_i32);
too_small!(small_u64, 7, 0, read_u64, write_u64);
too_small!(small_i64, 7, 0, read_i64, write_i64);
too_small!(small_f32, 3, 0.0, read_f32, write_f32);
too_small!(small_f64, 7, 0.0, read_f64, write_f64);
too_small!(small_uint_1, 1, read_uint);
too_small!(small_uint_2, 2, read_uint);
too_small!(small_uint_3, 3, read_uint);
too_small!(small_uint_4, 4, read_uint);
too_small!(small_uint_5, 5, read_uint);
too_small!(small_uint_6, 6, read_uint);
too_small!(small_uint_7, 7, read_uint);
too_small!(small_int_1, 1, read_int);
too_small!(small_int_2, 2, read_int);
too_small!(small_int_3, 3, read_int);
too_small!(small_int_4, 4, read_int);
too_small!(small_int_5, 5, read_int);
too_small!(small_int_6, 6, read_int);
too_small!(small_int_7, 7, read_int);
#[test]
fn uint_bigger_buffer() {
use {ByteOrder, LittleEndian};
let n = LittleEndian::read_uint(&[1, 2, 3, 4, 5, 6, 7, 8], 5);
assert_eq!(n, 0x0504030201);
}
}

View File

@ -0,0 +1,297 @@
use std::error;
use std::fmt;
use std::io;
use std::result;
use byteorder::ByteOrder;
/// A short-hand for `result::Result<T, byteorder::Error>`.
pub type Result<T> = result::Result<T, Error>;
/// An error type for reading bytes.
///
/// This is a thin wrapper over the standard `io::Error` type. Namely, it
/// adds one additional error case: an unexpected EOF.
///
/// Note that this error is also used for the `write` methods to keep things
/// consistent.
#[derive(Debug)]
pub enum Error {
/// An unexpected EOF.
///
/// This occurs when a call to the underlying reader returns `0` bytes,
/// but more bytes are required to decode a meaningful value.
UnexpectedEOF,
/// Any underlying IO error that occurs while reading bytes.
Io(io::Error),
}
impl From<io::Error> for Error {
fn from(err: io::Error) -> Error { Error::Io(err) }
}
impl From<Error> for io::Error {
fn from(err: Error) -> io::Error {
match err {
Error::Io(err) => err,
Error::UnexpectedEOF => io::Error::new(io::ErrorKind::Other,
"unexpected EOF")
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Error::UnexpectedEOF => write!(f, "Unexpected end of file."),
Error::Io(ref err) => err.fmt(f),
}
}
}
impl error::Error for Error {
fn description(&self) -> &str {
match *self {
Error::UnexpectedEOF => "Unexpected end of file.",
Error::Io(ref err) => error::Error::description(err),
}
}
fn cause(&self) -> Option<&error::Error> {
match *self {
Error::UnexpectedEOF => None,
Error::Io(ref err) => err.cause(),
}
}
}
/// Extends `Read` with methods for reading numbers. (For `std::io`.)
///
/// Most of the methods defined here have an unconstrained type parameter that
/// must be explicitly instantiated. Typically, it is instantiated with either
/// the `BigEndian` or `LittleEndian` types defined in this crate.
///
/// # Examples
///
/// Read unsigned 16 bit big-endian integers from a `Read`:
///
/// ```rust
/// use std::io::Cursor;
/// use byteorder::{BigEndian, ReadBytesExt};
///
/// let mut rdr = Cursor::new(vec![2, 5, 3, 0]);
/// assert_eq!(517, rdr.read_u16::<BigEndian>().unwrap());
/// assert_eq!(768, rdr.read_u16::<BigEndian>().unwrap());
/// ```
pub trait ReadBytesExt: io::Read {
/// Reads an unsigned 8 bit integer from the underlying reader.
///
/// Note that since this reads a single byte, no byte order conversions
/// are used. It is included for completeness.
fn read_u8(&mut self) -> Result<u8> {
let mut buf = [0; 1];
try!(read_full(self, &mut buf));
Ok(buf[0])
}
/// Reads a signed 8 bit integer from the underlying reader.
///
/// Note that since this reads a single byte, no byte order conversions
/// are used. It is included for completeness.
fn read_i8(&mut self) -> Result<i8> {
let mut buf = [0; 1];
try!(read_full(self, &mut buf));
Ok(buf[0] as i8)
}
/// Reads an unsigned 16 bit integer from the underlying reader.
fn read_u16<T: ByteOrder>(&mut self) -> Result<u16> {
let mut buf = [0; 2];
try!(read_full(self, &mut buf));
Ok(T::read_u16(&buf))
}
/// Reads a signed 16 bit integer from the underlying reader.
fn read_i16<T: ByteOrder>(&mut self) -> Result<i16> {
let mut buf = [0; 2];
try!(read_full(self, &mut buf));
Ok(T::read_i16(&buf))
}
/// Reads an unsigned 32 bit integer from the underlying reader.
fn read_u32<T: ByteOrder>(&mut self) -> Result<u32> {
let mut buf = [0; 4];
try!(read_full(self, &mut buf));
Ok(T::read_u32(&buf))
}
/// Reads a signed 32 bit integer from the underlying reader.
fn read_i32<T: ByteOrder>(&mut self) -> Result<i32> {
let mut buf = [0; 4];
try!(read_full(self, &mut buf));
Ok(T::read_i32(&buf))
}
/// Reads an unsigned 64 bit integer from the underlying reader.
fn read_u64<T: ByteOrder>(&mut self) -> Result<u64> {
let mut buf = [0; 8];
try!(read_full(self, &mut buf));
Ok(T::read_u64(&buf))
}
/// Reads a signed 64 bit integer from the underlying reader.
fn read_i64<T: ByteOrder>(&mut self) -> Result<i64> {
let mut buf = [0; 8];
try!(read_full(self, &mut buf));
Ok(T::read_i64(&buf))
}
/// Reads an unsigned n-bytes integer from the underlying reader.
fn read_uint<T: ByteOrder>(&mut self, nbytes: usize) -> Result<u64> {
let mut buf = [0; 8];
try!(read_full(self, &mut buf[..nbytes]));
Ok(T::read_uint(&buf[..nbytes], nbytes))
}
/// Reads a signed n-bytes integer from the underlying reader.
fn read_int<T: ByteOrder>(&mut self, nbytes: usize) -> Result<i64> {
let mut buf = [0; 8];
try!(read_full(self, &mut buf[..nbytes]));
Ok(T::read_int(&buf[..nbytes], nbytes))
}
/// Reads a IEEE754 single-precision (4 bytes) floating point number from
/// the underlying reader.
fn read_f32<T: ByteOrder>(&mut self) -> Result<f32> {
let mut buf = [0; 4];
try!(read_full(self, &mut buf));
Ok(T::read_f32(&buf))
}
/// Reads a IEEE754 double-precision (8 bytes) floating point number from
/// the underlying reader.
fn read_f64<T: ByteOrder>(&mut self) -> Result<f64> {
let mut buf = [0; 8];
try!(read_full(self, &mut buf));
Ok(T::read_f64(&buf))
}
}
/// All types that implement `Read` get methods defined in `ReadBytesExt`
/// for free.
impl<R: io::Read + ?Sized> ReadBytesExt for R {}
fn read_full<R: io::Read + ?Sized>(rdr: &mut R, buf: &mut [u8]) -> Result<()> {
let mut nread = 0usize;
while nread < buf.len() {
match rdr.read(&mut buf[nread..]) {
Ok(0) => return Err(Error::UnexpectedEOF),
Ok(n) => nread += n,
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {},
Err(e) => return Err(From::from(e))
}
}
Ok(())
}
fn write_all<W: io::Write + ?Sized>(wtr: &mut W, buf: &[u8]) -> Result<()> {
wtr.write_all(buf).map_err(From::from)
}
/// Extends `Write` with methods for writing numbers. (For `std::io`.)
///
/// Most of the methods defined here have an unconstrained type parameter that
/// must be explicitly instantiated. Typically, it is instantiated with either
/// the `BigEndian` or `LittleEndian` types defined in this crate.
///
/// # Examples
///
/// Write unsigned 16 bit big-endian integers to a `Write`:
///
/// ```rust
/// use byteorder::{BigEndian, WriteBytesExt};
///
/// let mut wtr = vec![];
/// wtr.write_u16::<BigEndian>(517).unwrap();
/// wtr.write_u16::<BigEndian>(768).unwrap();
/// assert_eq!(wtr, vec![2, 5, 3, 0]);
/// ```
pub trait WriteBytesExt: io::Write {
/// Writes an unsigned 8 bit integer to the underlying writer.
///
/// Note that since this writes a single byte, no byte order conversions
/// are used. It is included for completeness.
fn write_u8(&mut self, n: u8) -> Result<()> {
write_all(self, &[n])
}
/// Writes a signed 8 bit integer to the underlying writer.
///
/// Note that since this writes a single byte, no byte order conversions
/// are used. It is included for completeness.
fn write_i8(&mut self, n: i8) -> Result<()> {
write_all(self, &[n as u8])
}
/// Writes an unsigned 16 bit integer to the underlying writer.
fn write_u16<T: ByteOrder>(&mut self, n: u16) -> Result<()> {
let mut buf = [0; 2];
T::write_u16(&mut buf, n);
write_all(self, &buf)
}
/// Writes a signed 16 bit integer to the underlying writer.
fn write_i16<T: ByteOrder>(&mut self, n: i16) -> Result<()> {
let mut buf = [0; 2];
T::write_i16(&mut buf, n);
write_all(self, &buf)
}
/// Writes an unsigned 32 bit integer to the underlying writer.
fn write_u32<T: ByteOrder>(&mut self, n: u32) -> Result<()> {
let mut buf = [0; 4];
T::write_u32(&mut buf, n);
write_all(self, &buf)
}
/// Writes a signed 32 bit integer to the underlying writer.
fn write_i32<T: ByteOrder>(&mut self, n: i32) -> Result<()> {
let mut buf = [0; 4];
T::write_i32(&mut buf, n);
write_all(self, &buf)
}
/// Writes an unsigned 64 bit integer to the underlying writer.
fn write_u64<T: ByteOrder>(&mut self, n: u64) -> Result<()> {
let mut buf = [0; 8];
T::write_u64(&mut buf, n);
write_all(self, &buf)
}
/// Writes a signed 64 bit integer to the underlying writer.
fn write_i64<T: ByteOrder>(&mut self, n: i64) -> Result<()> {
let mut buf = [0; 8];
T::write_i64(&mut buf, n);
write_all(self, &buf)
}
/// Writes a IEEE754 single-precision (4 bytes) floating point number to
/// the underlying writer.
fn write_f32<T: ByteOrder>(&mut self, n: f32) -> Result<()> {
let mut buf = [0; 4];
T::write_f32(&mut buf, n);
write_all(self, &buf)
}
/// Writes a IEEE754 double-precision (8 bytes) floating point number to
/// the underlying writer.
fn write_f64<T: ByteOrder>(&mut self, n: f64) -> Result<()> {
let mut buf = [0; 8];
T::write_f64(&mut buf, n);
write_all(self, &buf)
}
}
/// All types that implement `Write` get methods defined in `WriteBytesExt`
/// for free.
impl<W: io::Write + ?Sized> WriteBytesExt for W {}