/rust/registry/src/index.crates.io-1949cf8c6b5b557f/fst-0.4.7/src/bytes.rs
Line | Count | Source |
1 | | use std::convert::TryInto; |
2 | | use 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] |
7 | 0 | pub fn read_u32_le(slice: &[u8]) -> u32 { |
8 | 0 | u32::from_le_bytes(slice[..4].try_into().unwrap()) |
9 | 0 | } |
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] |
14 | 0 | pub fn read_u64_le(slice: &[u8]) -> u64 { |
15 | 0 | u64::from_le_bytes(slice[..8].try_into().unwrap()) |
16 | 0 | } |
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] |
21 | 0 | pub fn write_u32_le(n: u32, slice: &mut [u8]) { |
22 | 0 | assert!(slice.len() >= 4); |
23 | 0 | let bytes = n.to_le_bytes(); |
24 | 0 | slice[0] = bytes[0]; |
25 | 0 | slice[1] = bytes[1]; |
26 | 0 | slice[2] = bytes[2]; |
27 | 0 | slice[3] = bytes[3]; |
28 | 0 | } |
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] |
33 | 0 | pub fn io_write_u32_le<W: io::Write>(n: u32, mut wtr: W) -> io::Result<()> { |
34 | 0 | let mut buf = [0; 4]; |
35 | 0 | write_u32_le(n, &mut buf); |
36 | 0 | wtr.write_all(&buf) |
37 | 0 | } |
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] |
42 | 0 | pub fn write_u64_le(n: u64, slice: &mut [u8]) { |
43 | 0 | assert!(slice.len() >= 8); |
44 | 0 | let bytes = n.to_le_bytes(); |
45 | 0 | slice[0] = bytes[0]; |
46 | 0 | slice[1] = bytes[1]; |
47 | 0 | slice[2] = bytes[2]; |
48 | 0 | slice[3] = bytes[3]; |
49 | 0 | slice[4] = bytes[4]; |
50 | 0 | slice[5] = bytes[5]; |
51 | 0 | slice[6] = bytes[6]; |
52 | 0 | slice[7] = bytes[7]; |
53 | 0 | } |
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] |
58 | 0 | pub fn io_write_u64_le<W: io::Write>(n: u64, mut wtr: W) -> io::Result<()> { |
59 | 0 | let mut buf = [0; 8]; |
60 | 0 | write_u64_le(n, &mut buf); |
61 | 0 | wtr.write_all(&buf) |
62 | 0 | } |
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] |
68 | 0 | pub fn pack_uint<W: io::Write>(wtr: W, n: u64) -> io::Result<u8> { |
69 | 0 | let nbytes = pack_size(n); |
70 | 0 | pack_uint_in(wtr, n, nbytes).map(|_| nbytes) |
71 | 0 | } |
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] |
79 | 0 | pub fn pack_uint_in<W: io::Write>( |
80 | 0 | mut wtr: W, |
81 | 0 | mut n: u64, |
82 | 0 | nbytes: u8, |
83 | 0 | ) -> io::Result<()> { |
84 | 0 | assert!(1 <= nbytes && nbytes <= 8); |
85 | 0 | let mut buf = [0u8; 8]; |
86 | 0 | for i in 0..nbytes { |
87 | 0 | buf[i as usize] = n as u8; |
88 | 0 | n = n >> 8; |
89 | 0 | } |
90 | 0 | wtr.write_all(&buf[..nbytes as usize])?; |
91 | 0 | Ok(()) |
92 | 0 | } |
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] |
99 | 0 | pub fn unpack_uint(slice: &[u8], nbytes: u8) -> u64 { |
100 | 0 | assert!(1 <= nbytes && nbytes <= 8); |
101 | | |
102 | 0 | let mut n = 0; |
103 | 0 | for (i, &b) in slice[..nbytes as usize].iter().enumerate() { |
104 | 0 | n = n | ((b as u64) << (8 * i)); |
105 | 0 | } |
106 | 0 | n |
107 | 0 | } |
108 | | |
109 | | /// pack_size returns the smallest number of bytes that can encode `n`. |
110 | | #[inline] |
111 | 0 | pub fn pack_size(n: u64) -> u8 { |
112 | 0 | if n < 1 << 8 { |
113 | 0 | 1 |
114 | 0 | } else if n < 1 << 16 { |
115 | 0 | 2 |
116 | 0 | } else if n < 1 << 24 { |
117 | 0 | 3 |
118 | 0 | } else if n < 1 << 32 { |
119 | 0 | 4 |
120 | 0 | } else if n < 1 << 40 { |
121 | 0 | 5 |
122 | 0 | } else if n < 1 << 48 { |
123 | 0 | 6 |
124 | 0 | } else if n < 1 << 56 { |
125 | 0 | 7 |
126 | | } else { |
127 | 0 | 8 |
128 | | } |
129 | 0 | } |
130 | | |
131 | | #[cfg(test)] |
132 | | mod 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 | | } |