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