fst/
bytes.rs

1use std::convert::TryInto;
2use std::io;
3
4/// Read a u32 in little endian format from the beginning of the given slice.
5/// This panics if the slice has length less than 4.
6#[inline]
7pub fn read_u32_le(slice: &[u8]) -> u32 {
8    u32::from_le_bytes(slice[..4].try_into().unwrap())
9}
10
11/// Read a u64 in little endian format from the beginning of the given slice.
12/// This panics if the slice has length less than 8.
13#[inline]
14pub fn read_u64_le(slice: &[u8]) -> u64 {
15    u64::from_le_bytes(slice[..8].try_into().unwrap())
16}
17
18/// Write a u32 in little endian format to the beginning of the given slice.
19/// This panics if the slice has length less than 4.
20#[inline]
21pub fn write_u32_le(n: u32, slice: &mut [u8]) {
22    assert!(slice.len() >= 4);
23    let bytes = n.to_le_bytes();
24    slice[0] = bytes[0];
25    slice[1] = bytes[1];
26    slice[2] = bytes[2];
27    slice[3] = bytes[3];
28}
29
30/// Like write_u32_le, but to an io::Write implementation. If every byte could
31/// not be writen, then this returns an error.
32#[inline]
33pub fn io_write_u32_le<W: io::Write>(n: u32, mut wtr: W) -> io::Result<()> {
34    let mut buf = [0; 4];
35    write_u32_le(n, &mut buf);
36    wtr.write_all(&buf)
37}
38
39/// Write a u64 in little endian format to the beginning of the given slice.
40/// This panics if the slice has length less than 8.
41#[inline]
42pub fn write_u64_le(n: u64, slice: &mut [u8]) {
43    assert!(slice.len() >= 8);
44    let bytes = n.to_le_bytes();
45    slice[0] = bytes[0];
46    slice[1] = bytes[1];
47    slice[2] = bytes[2];
48    slice[3] = bytes[3];
49    slice[4] = bytes[4];
50    slice[5] = bytes[5];
51    slice[6] = bytes[6];
52    slice[7] = bytes[7];
53}
54
55/// Like write_u64_le, but to an io::Write implementation. If every byte could
56/// not be writen, then this returns an error.
57#[inline]
58pub fn io_write_u64_le<W: io::Write>(n: u64, mut wtr: W) -> io::Result<()> {
59    let mut buf = [0; 8];
60    write_u64_le(n, &mut buf);
61    wtr.write_all(&buf)
62}
63
64/// pack_uint packs the given integer in the smallest number of bytes possible,
65/// and writes it to the given writer. The number of bytes written is returned
66/// on success.
67#[inline]
68pub fn pack_uint<W: io::Write>(wtr: W, n: u64) -> io::Result<u8> {
69    let nbytes = pack_size(n);
70    pack_uint_in(wtr, n, nbytes).map(|_| nbytes)
71}
72
73/// pack_uint_in is like pack_uint, but always uses the number of bytes given
74/// to pack the number given.
75///
76/// `nbytes` must be >= pack_size(n) and <= 8, where `pack_size(n)` is the
77/// smallest number of bytes that can store the integer given.
78#[inline]
79pub fn pack_uint_in<W: io::Write>(
80    mut wtr: W,
81    mut n: u64,
82    nbytes: u8,
83) -> io::Result<()> {
84    assert!(1 <= nbytes && nbytes <= 8);
85    let mut buf = [0u8; 8];
86    for i in 0..nbytes {
87        buf[i as usize] = n as u8;
88        n = n >> 8;
89    }
90    wtr.write_all(&buf[..nbytes as usize])?;
91    Ok(())
92}
93
94/// unpack_uint is the dual of pack_uint. It unpacks the integer at the current
95/// position in `slice` after reading `nbytes` bytes.
96///
97/// `nbytes` must be >= 1 and <= 8.
98#[inline]
99pub fn unpack_uint(slice: &[u8], nbytes: u8) -> u64 {
100    assert!(1 <= nbytes && nbytes <= 8);
101
102    let mut n = 0;
103    for (i, &b) in slice[..nbytes as usize].iter().enumerate() {
104        n = n | ((b as u64) << (8 * i));
105    }
106    n
107}
108
109/// pack_size returns the smallest number of bytes that can encode `n`.
110#[inline]
111pub fn pack_size(n: u64) -> u8 {
112    if n < 1 << 8 {
113        1
114    } else if n < 1 << 16 {
115        2
116    } else if n < 1 << 24 {
117        3
118    } else if n < 1 << 32 {
119        4
120    } else if n < 1 << 40 {
121        5
122    } else if n < 1 << 48 {
123        6
124    } else if n < 1 << 56 {
125        7
126    } else {
127        8
128    }
129}
130
131#[cfg(test)]
132mod tests {
133    use super::*;
134    use quickcheck::{QuickCheck, StdGen};
135    use std::io;
136
137    #[test]
138    fn prop_pack_in_out() {
139        fn p(num: u64) -> bool {
140            let mut buf = io::Cursor::new(vec![]);
141            let size = pack_uint(&mut buf, num).unwrap();
142            buf.set_position(0);
143            num == unpack_uint(buf.get_ref(), size)
144        }
145        QuickCheck::new()
146            .gen(StdGen::new(::rand::thread_rng(), 257)) // pick byte boundary
147            .quickcheck(p as fn(u64) -> bool);
148    }
149}