1pub const fn assemble_u16_le(bytes: [u8; 2]) -> u16 {
9 u16::from_le_bytes(bytes)
11}
12
13pub const fn assemble_u16_be(bytes: [u8; 2]) -> u16 {
15 u16::from_be_bytes(bytes)
17}
18
19pub const fn assemble_u24_le(bytes: [u8; 3]) -> u32 {
21 u32::from_le_bytes([bytes[0], bytes[1], bytes[2], 0])
23}
24
25pub const fn assemble_u24_be(bytes: [u8; 3]) -> u32 {
27 u32::from_be_bytes([0, bytes[0], bytes[1], bytes[2]])
29}
30
31pub const fn assemble_u32_le(bytes: [u8; 4]) -> u32 {
33 u32::from_le_bytes(bytes)
35}
36
37pub const fn assemble_u32_be(bytes: [u8; 4]) -> u32 {
39 u32::from_be_bytes(bytes)
41}
42
43pub const fn assemble_u64_le(bytes: [u8; 8]) -> u64 {
45 u64::from_le_bytes(bytes)
47}
48
49pub const fn assemble_u64_be(bytes: [u8; 8]) -> u64 {
51 u64::from_be_bytes(bytes)
53}
54
55pub const fn assemble_f32_le(bytes: [u8; 4]) -> f32 {
57 f32::from_bits(assemble_u32_le(bytes))
58}
59
60pub const fn assemble_f32_be(bytes: [u8; 4]) -> f32 {
62 f32::from_bits(assemble_u32_be(bytes))
63}
64
65pub const fn assemble_f64_le(bytes: [u8; 8]) -> f64 {
67 f64::from_bits(assemble_u64_le(bytes))
68}
69
70pub const fn assemble_f64_be(bytes: [u8; 8]) -> f64 {
72 f64::from_bits(assemble_u64_be(bytes))
73}
74
75pub fn find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
77 if needle.is_empty() {
78 return None;
79 }
80 memchr::memmem::find(haystack, needle)
81}
82
83pub fn find_from(haystack: &[u8], needle: &[u8], from: usize) -> Option<usize> {
85 let tail = haystack.get(from..)?;
86 find(tail, needle).map(|relative| from + relative)
87}
88
89pub fn find_in(haystack: &[u8], needle: &[u8], start: usize, end: usize) -> Option<usize> {
91 let window = haystack.get(start..end)?;
92 find(window, needle).map(|relative| start + relative)
93}
94
95pub fn contains(haystack: &[u8], needle: &[u8]) -> bool {
97 find(haystack, needle).is_some()
98}
99
100pub fn find_iter<'a>(haystack: &'a [u8], needle: &'a [u8]) -> impl Iterator<Item = usize> + 'a {
104 let search = if needle.is_empty() {
105 None
106 } else {
107 Some(memchr::memmem::find_iter(haystack, needle))
108 };
109 search.into_iter().flatten()
110}
111
112#[cfg(test)]
113mod tests {
114 use super::{contains, find, find_from, find_in, find_iter};
115
116 #[test]
117 fn assembles_wire_byte_orders_without_host_endian_assumptions() {
118 assert_eq!(super::assemble_u16_le([0x02, 0x01]), 0x0102);
119 assert_eq!(super::assemble_u24_be([0x01, 0x02, 0x03]), 0x0001_0203);
120 assert_eq!(
121 super::assemble_u32_be([0x01, 0x02, 0x03, 0x04]),
122 0x0102_0304
123 );
124 assert_eq!(super::assemble_u64_le([1, 0, 0, 0, 0, 0, 0, 0]), 1);
125 assert_eq!(super::assemble_f32_be([0x3f, 0xc0, 0, 0]), 1.5);
126 assert_eq!(super::assemble_f64_le([0, 0, 0, 0, 0, 0, 0xf0, 0x3f]), 1.0);
127 }
128
129 #[test]
130 fn empty_needle_is_never_a_match() {
131 assert_eq!(find(b"abc", b""), None);
132 assert_eq!(find_from(b"abc", b"", 1), None);
133 assert_eq!(find_in(b"abc", b"", 0, 3), None);
134 assert!(!contains(b"abc", b""));
135 assert_eq!(
136 find_iter(b"abc", b"").collect::<Vec<_>>(),
137 Vec::<usize>::new()
138 );
139 }
140
141 #[test]
142 fn finds_absolute_and_ranged_offsets() {
143 let haystack = b"xxabcxxabc";
144 assert_eq!(find(haystack, b"abc"), Some(2));
145 assert_eq!(find_from(haystack, b"abc", 3), Some(7));
146 assert_eq!(find_in(haystack, b"abc", 3, 10), Some(7));
147 assert_eq!(find_in(haystack, b"abc", 3, 6), None);
148 assert!(contains(haystack, b"abc"));
149 assert_eq!(find_iter(haystack, b"abc").collect::<Vec<_>>(), [2, 7]);
150 }
151}