1use bytes::Bytes;
19
20use crate::error::{Error, Result};
21
22pub struct LeCursor<'a> {
27 buf: &'a [u8],
28 pos: usize,
29 base: u64,
31 path: &'a str,
32}
33
34impl<'a> LeCursor<'a> {
35 pub fn new(buf: &'a [u8], base: u64, path: &'a str) -> Self {
36 Self {
37 buf,
38 pos: 0,
39 base,
40 path,
41 }
42 }
43
44 pub fn position(&self) -> usize {
45 self.pos
46 }
47
48 pub fn file_offset(&self) -> u64 {
49 self.base + self.pos as u64
50 }
51
52 pub fn remaining(&self) -> usize {
53 self.buf.len() - self.pos
54 }
55
56 pub fn is_empty(&self) -> bool {
57 self.remaining() == 0
58 }
59
60 pub fn seek(&mut self, pos: usize) -> Result<()> {
61 if pos > self.buf.len() {
62 return Err(self.short(pos - self.buf.len(), "seek"));
63 }
64 self.pos = pos;
65 Ok(())
66 }
67
68 pub fn skip(&mut self, n: usize) -> Result<()> {
69 let pos = self
74 .pos
75 .checked_add(n)
76 .ok_or_else(|| self.short(n, "skip"))?;
77 self.seek(pos)
78 }
79
80 pub fn take(&mut self, n: usize) -> Result<&'a [u8]> {
81 let end = self
82 .pos
83 .checked_add(n)
84 .ok_or_else(|| self.short(n, "take"))?;
85 if end > self.buf.len() {
86 return Err(self.short(n, "take"));
87 }
88 let out = &self.buf[self.pos..end];
89 self.pos = end;
90 Ok(out)
91 }
92
93 pub fn take_cstr(&mut self) -> Result<&'a str> {
96 let rest = &self.buf[self.pos..];
97 let nul = memchr::memchr(0, rest).ok_or_else(|| self.corrupt("unterminated string"))?;
98 let out = std::str::from_utf8(&rest[..nul])
99 .map_err(|_| self.corrupt("string is not valid UTF-8"))?;
100 self.pos += nul + 1;
101 Ok(out)
102 }
103
104 pub fn take_padded_str(&mut self, width: usize) -> Result<&'a str> {
107 let field = self.take(width)?;
108 let end = memchr::memchr(0, field).unwrap_or(width);
109 std::str::from_utf8(&field[..end]).map_err(|_| self.corrupt("string is not valid UTF-8"))
110 }
111
112 fn short(&self, wanted: usize, what: &str) -> Error {
113 Error::corrupt(
114 self.path,
115 self.file_offset(),
116 format!(
117 "{what} of {wanted} bytes with {} left in a {}-byte buffer",
118 self.remaining(),
119 self.buf.len()
120 ),
121 )
122 }
123
124 fn corrupt(&self, what: &str) -> Error {
125 Error::corrupt(self.path, self.file_offset(), what)
126 }
127}
128
129macro_rules! le_readers {
132 ($($name:ident, $peek:ident => $t:ty),* $(,)?) => {
133 impl LeCursor<'_> {
134 $(
135 #[inline]
136 pub fn $name(&mut self) -> Result<$t> {
137 const N: usize = std::mem::size_of::<$t>();
138 let bytes = self.take(N)?;
139 let mut arr = [0u8; N];
140 arr.copy_from_slice(bytes);
141 Ok(<$t>::from_le_bytes(arr))
142 }
143
144 #[inline]
145 pub fn $peek(&self) -> Result<$t> {
146 const N: usize = std::mem::size_of::<$t>();
147 if self.remaining() < N {
148 return Err(self.short(N, stringify!($peek)));
149 }
150 let mut arr = [0u8; N];
151 arr.copy_from_slice(&self.buf[self.pos..self.pos + N]);
152 Ok(<$t>::from_le_bytes(arr))
153 }
154 )*
155 }
156 };
157}
158
159le_readers! {
160 read_u8, peek_u8 => u8,
161 read_i8, peek_i8 => i8,
162 read_u16, peek_u16 => u16,
163 read_i16, peek_i16 => i16,
164 read_u32, peek_u32 => u32,
165 read_i32, peek_i32 => i32,
166 read_u64, peek_u64 => u64,
167 read_i64, peek_i64 => i64,
168 read_f32, peek_f32 => f32,
169 read_f64, peek_f64 => f64,
170}
171
172#[derive(Default)]
176pub struct LeBuf {
177 buf: Vec<u8>,
178}
179
180impl LeBuf {
181 pub fn new() -> Self {
182 Self::default()
183 }
184
185 pub fn with_capacity(n: usize) -> Self {
186 Self {
187 buf: Vec::with_capacity(n),
188 }
189 }
190
191 pub fn len(&self) -> usize {
192 self.buf.len()
193 }
194
195 pub fn is_empty(&self) -> bool {
196 self.buf.is_empty()
197 }
198
199 pub fn clear(&mut self) {
200 self.buf.clear();
201 }
202
203 pub fn as_slice(&self) -> &[u8] {
204 &self.buf
205 }
206
207 pub fn into_bytes(self) -> Bytes {
208 Bytes::from(self.buf)
209 }
210
211 pub fn put_bytes(&mut self, data: &[u8]) {
212 self.buf.extend_from_slice(data);
213 }
214
215 pub fn put_zeros(&mut self, n: usize) {
216 self.buf.resize(self.buf.len() + n, 0);
217 }
218
219 pub fn put_padded_str(&mut self, s: &str, width: usize) -> Result<()> {
224 if s.len() > width {
225 return Err(Error::invalid(format!(
226 "chromosome name {s:?} is longer than the {width}-byte key field"
227 )));
228 }
229 self.buf.extend_from_slice(s.as_bytes());
230 self.put_zeros(width - s.len());
231 Ok(())
232 }
233}
234
235macro_rules! le_writers {
236 ($($name:ident, $set:ident => $t:ty),* $(,)?) => {
237 impl LeBuf {
238 $(
239 #[inline]
240 pub fn $name(&mut self, value: $t) {
241 self.buf.extend_from_slice(&value.to_le_bytes());
242 }
243
244 #[inline]
247 pub fn $set(&mut self, offset: usize, value: $t) {
248 let bytes = value.to_le_bytes();
249 self.buf[offset..offset + bytes.len()].copy_from_slice(&bytes);
250 }
251 )*
252 }
253 };
254}
255
256le_writers! {
257 put_u8, set_u8 => u8,
258 put_u16, set_u16 => u16,
259 put_u32, set_u32 => u32,
260 put_i32, set_i32 => i32,
261 put_u64, set_u64 => u64,
262 put_i64, set_i64 => i64,
263 put_f32, set_f32 => f32,
264 put_f64, set_f64 => f64,
265}