Skip to main content

bit_buf/
write.rs

1use crate::{BitBuf, Error, Result, StorageMut};
2
3impl<S: StorageMut> BitBuf<S> {
4  /// Write a [`u8`] in BE-bit-order at `byte_offset` without performing bound checks
5  ///
6  /// # Safety
7  ///
8  /// * This is UB if [`byte_offset >= self.bytes().len()`][Self::bytes]
9  ///
10  /// # Panics
11  ///
12  /// * Panics in debug mode if [`byte_offset >= self.bytes().len()`][Self::bytes]
13  #[inline(always)]
14  pub unsafe fn write_u8_be_aligned_at_unchecked(
15    &mut self,
16    byte_offset: usize,
17    v: u8,
18  ) -> &mut Self {
19    let bytes = self.bytes_mut();
20
21    debug_assert!(
22      byte_offset < bytes.len(),
23      "BitBuf::write_u8_be_aligned_at_unchecked: index out of bounds! len is {}, offset is {}",
24      bytes.len(),
25      byte_offset,
26    );
27
28    unsafe { *bytes.get_unchecked_mut(byte_offset) = v };
29    self
30  }
31
32  /// Write a [`u8`] in BE-bit-order without performing bound checks, advancing the internal cursor
33  ///
34  /// # Safety
35  ///
36  /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
37  /// * This is UB if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] >= [self.bytes().len()][Self::bytes]</code>)
38  ///
39  /// # Panics
40  ///
41  /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
42  /// * Panics in debug mode if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] >= [self.bytes().len()][Self::bytes]</code>)
43  #[inline(always)]
44  pub unsafe fn write_u8_be_aligned_unchecked(&mut self, v: u8) -> &mut Self {
45    debug_assert!(
46      self.is_aligned(),
47      "BitBuf::write_u8_be_aligned_unchecked called at unaligned bit position: {}",
48      self.pos(),
49    );
50
51    unsafe { self.write_u8_be_aligned_at_unchecked(self.byte_pos(), v) };
52    self.advance_bytes(1);
53    self
54  }
55
56  /// Write a [`u8`] in BE-bit-order at `offset` without performing bound checks
57  ///
58  /// # Safety
59  ///
60  /// * This is UB if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
61  /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
62  ///
63  /// # Panics
64  ///
65  /// * Panics in debug mode if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
66  /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
67  #[inline(always)]
68  pub unsafe fn write_u8_be_at_unchecked(&mut self, offset: usize, v: u8) -> &mut Self {
69    let byte_idx = offset / 8;
70    let shift = offset % 8;
71
72    let bytes = self.bytes_mut();
73
74    debug_assert!(
75      byte_idx < bytes.len(),
76      "BitBuf::write_u8_be_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
77      bytes.len(),
78      byte_idx,
79    );
80
81    if shift == 0 {
82      unsafe { self.write_u8_be_aligned_at_unchecked(byte_idx, v) };
83    } else {
84      let next_idx = byte_idx + 1;
85
86      debug_assert!(
87        next_idx < bytes.len(),
88        "BitBuf::write_u8_be_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
89        bytes.len(),
90        next_idx,
91      );
92
93      // first byte, higher part of value
94      unsafe {
95        // mask to keep high bits of the current byte
96        let mask = !0 << (8 - shift);
97        let b = bytes.get_unchecked(byte_idx) & mask;
98        // high bits of the value, shifted down
99        let new = v >> shift;
100        *bytes.get_unchecked_mut(byte_idx) = b | new;
101      }
102
103      // second byte, lower part of value
104      unsafe {
105        // mask to keep low bits of the current byte
106        let mask = !0 >> shift;
107        let b = bytes.get_unchecked(next_idx) & mask;
108        // low bits of the value, shifted up
109        let new = v << (8 - shift);
110        *bytes.get_unchecked_mut(next_idx) = b | new;
111      }
112    }
113
114    self
115  }
116
117  /// Write a [`u8`] in BE-bit-order without performing bound checks, advancing the internal cursor
118  ///
119  /// # Safety
120  ///
121  /// * This is UB if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
122  /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
123  ///
124  /// # Panics
125  ///
126  /// * Panics in debug mode if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
127  /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
128  #[inline(always)]
129  pub unsafe fn write_u8_be_unchecked(&mut self, v: u8) -> &mut Self {
130    unsafe { self.write_u8_be_at_unchecked(self.pos(), v) };
131    self.advance_bytes(1);
132    self
133  }
134
135  /// Write a BE-bit-order [`u8`] at `offset` while performing bound checks
136  ///
137  /// # Errors
138  ///
139  /// * Returns [`Error::OutOfBounds`]
140  ///   * if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
141  ///   * if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
142  #[inline(always)]
143  pub fn try_write_u8_be_at(&mut self, offset: usize, v: u8) -> Result<&mut Self> {
144    let byte_idx = offset / 8;
145    let shift = offset % 8;
146
147    let len = self.bytes().len();
148
149    if byte_idx >= len {
150      return Err(Error::OutOfBounds);
151    }
152
153    if shift != 0 && byte_idx + 1 >= len {
154      return Err(Error::OutOfBounds);
155    }
156
157    Ok(unsafe { self.write_u8_be_at_unchecked(offset, v) })
158  }
159
160  /// Write a BE-bit-order [`u8`] while performing bound checks, advancing the internal cursor
161  ///
162  /// # Errors
163  ///
164  /// * Returns [`Error::OutOfBounds`]
165  ///   * if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
166  ///   * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
167  #[inline(always)]
168  pub fn try_write_u8_be(&mut self, v: u8) -> Result<&mut Self> {
169    self.try_write_u8_be_at(self.pos(), v)?;
170    self.advance_bytes(1);
171    Ok(self)
172  }
173
174  /// Write a BE-bit-order [`u8`] at `offset`, panicking on out of bounds
175  ///
176  /// # Panics
177  ///
178  /// * Panics if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
179  /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
180  #[inline(always)]
181  pub fn write_u8_be_at(&mut self, offset: usize, v: u8) -> &mut Self {
182    self
183      .try_write_u8_be_at(offset, v)
184      .expect("BitBuf::write_u8_be_at out of bounds")
185  }
186
187  /// Write a BE-bit-order [`u8`], panicking on out of bounds, advancing the internal cursor
188  ///
189  /// # Panics
190  ///
191  /// * Panics if <code>(self.pos() / 8) >= [`self.bytes().len()`][Self::bytes]</code>
192  /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
193  #[inline(always)]
194  pub fn write_u8_be(&mut self, v: u8) -> &mut Self {
195    self
196      .try_write_u8_be(v)
197      .expect("BitBuf::write_u8_be out of bounds")
198  }
199
200  /// Write a [`u16`] in [BE-bit, BE-byte] order at `byte_offset` without performing bound checks
201  ///
202  /// # Safety
203  ///
204  /// * This is UB if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
205  ///
206  /// # Panics
207  ///
208  /// * Panics in debug mode if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
209  #[inline(always)]
210  pub unsafe fn write_u16_be_aligned_at_unchecked(
211    &mut self,
212    byte_offset: usize,
213    v: u16,
214  ) -> &mut Self {
215    let bytes = self.bytes_mut();
216
217    debug_assert!(
218      byte_offset + 1 < bytes.len(),
219      "BitBuf::write_u16_be_aligned_at_unchecked: index out of bounds! len is {}, offset is {}",
220      bytes.len(),
221      byte_offset + 1,
222    );
223
224    let [high, low] = v.to_be_bytes();
225
226    unsafe {
227      *bytes.get_unchecked_mut(byte_offset) = high;
228      *bytes.get_unchecked_mut(byte_offset + 1) = low;
229    }
230
231    self
232  }
233
234  /// Write a [`u16`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
235  ///
236  /// # Safety
237  ///
238  /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
239  /// * This is UB if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 1 >= [self.bytes().len()][Self::bytes]</code>)
240  ///
241  /// # Panics
242  ///
243  /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
244  /// * Panics in debug mode if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 1 >= [self.bytes().len()][Self::bytes]</code>)
245  #[inline(always)]
246  pub unsafe fn write_u16_be_aligned_unchecked(&mut self, v: u16) -> &mut Self {
247    debug_assert!(
248      self.is_aligned(),
249      "BitBuf::write_u16_be_aligned_unchecked called at unaligned bit position: {}",
250      self.pos(),
251    );
252
253    unsafe { self.write_u16_be_aligned_at_unchecked(self.byte_pos(), v) };
254    self.advance_bytes(2);
255    self
256  }
257
258  /// Write a [`u16`] in [BE-bit, BE-byte] order at `offset` without performing bound checks
259  ///
260  /// # Safety
261  ///
262  /// * This is UB if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
263  /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
264  ///
265  /// # Panics
266  ///
267  /// * Panics in debug mode if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
268  /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
269  #[inline(always)]
270  pub unsafe fn write_u16_be_at_unchecked(&mut self, offset: usize, v: u16) -> &mut Self {
271    let first_idx = offset / 8;
272    let shift = offset % 8;
273
274    let bytes = self.bytes_mut();
275
276    debug_assert!(
277      first_idx + 1 < bytes.len(),
278      "BitBuf::write_u16_be_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
279      bytes.len(),
280      first_idx + 1,
281    );
282
283    if shift == 0 {
284      unsafe { self.write_u16_be_aligned_at_unchecked(first_idx, v) };
285    } else {
286      let second_idx = first_idx + 1;
287      let third_idx = first_idx + 2;
288
289      debug_assert!(
290        third_idx < bytes.len(),
291        "BitBuf::write_u16_be_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
292        bytes.len(),
293        third_idx,
294      );
295
296      let [high, low] = v.to_be_bytes();
297
298      // first byte, higher part of value
299      unsafe {
300        // mask to keep high bits of the current byte
301        let mask = !0 << (8 - shift);
302        let b = bytes.get_unchecked(first_idx) & mask;
303        // high bits of the value, shifted down
304        let new = high >> shift;
305        *bytes.get_unchecked_mut(first_idx) = b | new;
306      }
307
308      // second byte, middle part of value
309      unsafe {
310        // no need to grab byte since all 8 bits will be overwritten
311        // high middle bits of the value, shifted up
312        let b_high = high << (8 - shift);
313        // low middle bits of the value, shifted down
314        let b_low = low >> shift;
315        *bytes.get_unchecked_mut(second_idx) = b_high | b_low;
316      }
317
318      // third byte, lower part of value
319      unsafe {
320        // mask to keep low bits of the current byte
321        let mask = !0 >> shift;
322        let b = bytes.get_unchecked(third_idx) & mask;
323        // low bits of the value, shifted up
324        let new = low << (8 - shift);
325        *bytes.get_unchecked_mut(third_idx) = b | new;
326      }
327    }
328
329    self
330  }
331
332  /// Write a [`u16`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
333  ///
334  /// # Safety
335  ///
336  /// * This is UB if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
337  /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
338  ///
339  /// # Panics
340  ///
341  /// * Panics in debug mode if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
342  /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
343  #[inline(always)]
344  pub unsafe fn write_u16_be_unchecked(&mut self, v: u16) -> &mut Self {
345    unsafe { self.write_u16_be_at_unchecked(self.pos(), v) };
346    self.advance_bytes(2);
347    self
348  }
349
350  /// Write a [BE-bit, BE-byte] order [`u16`] at `offset` while performing bound checks
351  ///
352  /// # Errors
353  ///
354  /// * Returns [`Error::OutOfBounds`]
355  ///   * if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
356  ///   * if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
357  #[inline(always)]
358  pub fn try_write_u16_be_at(&mut self, offset: usize, v: u16) -> Result<&mut Self> {
359    let first_idx = offset / 8;
360    let shift = offset % 8;
361
362    let len = self.bytes().len();
363
364    if first_idx + 1 >= len {
365      return Err(Error::OutOfBounds);
366    }
367
368    if shift != 0 && first_idx + 2 >= len {
369      return Err(Error::OutOfBounds);
370    }
371
372    Ok(unsafe { self.write_u16_be_at_unchecked(offset, v) })
373  }
374
375  /// Write a [BE-bit, BE-byte] order [`u16`] while performing bound checks, advancing the internal cursor
376  ///
377  /// # Errors
378  ///
379  /// * Returns [`Error::OutOfBounds`]
380  ///   * if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
381  ///   * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
382  #[inline(always)]
383  pub fn try_write_u16_be(&mut self, v: u16) -> Result<&mut Self> {
384    self.try_write_u16_be_at(self.pos(), v)?;
385    self.advance_bytes(2);
386    Ok(self)
387  }
388
389  /// Write a [BE-bit, BE-byte] order [`u16`] at `offset`, panicking on out of bounds
390  ///
391  /// # Panics
392  ///
393  /// * Panics if <code>(offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
394  /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
395  #[inline(always)]
396  pub fn write_u16_be_at(&mut self, offset: usize, v: u16) -> &mut Self {
397    self
398      .try_write_u16_be_at(offset, v)
399      .expect("BitBuf::write_u16_be_at out of bounds")
400  }
401
402  /// Write a [BE-bit, BE-byte] order [`u16`], panicking on out of bounds, advancing the internal cursor
403  ///
404  /// # Panics
405  ///
406  /// * Panics if <code>(self.pos() / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
407  /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 2 >= [`self.bytes().len()`][Self::bytes]</code>
408  #[inline(always)]
409  pub fn write_u16_be(&mut self, v: u16) -> &mut Self {
410    self
411      .try_write_u16_be(v)
412      .expect("BitBuf::write_u16_be out of bounds")
413  }
414
415  /// Write a [`u32`] in [BE-bit, BE-byte] order at `byte_offset` without performing bound checks
416  ///
417  /// # Safety
418  ///
419  /// * This is UB if [`byte_offset + 3 >= self.bytes().len()`][Self::bytes]
420  ///
421  /// # Panics
422  ///
423  /// * Panics in debug mode if [`byte_offset + 3 >= self.bytes().len()`][Self::bytes]
424  #[inline(always)]
425  pub unsafe fn write_u32_be_aligned_at_unchecked(
426    &mut self,
427    byte_offset: usize,
428    v: u32,
429  ) -> &mut Self {
430    let bytes = self.bytes_mut();
431
432    debug_assert!(
433      byte_offset + 3 < bytes.len(),
434      "BitBuf::write_u32_be_aligned_at_unchecked: index out of bounds! len is {}, offset is {}",
435      bytes.len(),
436      byte_offset + 3,
437    );
438
439    let [a, b, c, d] = v.to_be_bytes();
440
441    unsafe {
442      *bytes.get_unchecked_mut(byte_offset) = a;
443      *bytes.get_unchecked_mut(byte_offset + 1) = b;
444      *bytes.get_unchecked_mut(byte_offset + 2) = c;
445      *bytes.get_unchecked_mut(byte_offset + 3) = d;
446    }
447
448    self
449  }
450
451  /// Write a [`u32`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
452  ///
453  /// # Safety
454  ///
455  /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
456  /// * This is UB if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 3 >= [self.bytes().len()][Self::bytes]</code>)
457  ///
458  /// # Panics
459  ///
460  /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
461  /// * Panics in debug mode if the internal cursor points past the end of storage (<code>[self.byte_pos()][Self::byte_pos] + 3 >= [self.bytes().len()][Self::bytes]</code>)
462  #[inline(always)]
463  pub unsafe fn write_u32_be_aligned_unchecked(&mut self, v: u32) -> &mut Self {
464    debug_assert!(
465      self.is_aligned(),
466      "BitBuf::write_u32_be_aligned_unchecked called at unaligned bit position: {}",
467      self.pos(),
468    );
469
470    unsafe { self.write_u32_be_aligned_at_unchecked(self.byte_pos(), v) };
471    self.advance_bytes(4);
472    self
473  }
474
475  /// Write a [`u32`] in [BE-bit, BE-byte] order at `offset` without performing bound checks
476  ///
477  /// # Safety
478  ///
479  /// * This is UB if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
480  /// * This is UB if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
481  ///
482  /// # Panics
483  ///
484  /// * Panics in debug mode if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
485  /// * Panics in debug mode if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
486  #[inline(always)]
487  pub unsafe fn write_u32_be_at_unchecked(&mut self, offset: usize, v: u32) -> &mut Self {
488    let first_idx = offset / 8;
489    let shift = offset % 8;
490
491    let bytes = self.bytes_mut();
492
493    debug_assert!(
494      first_idx + 3 < bytes.len(),
495      "BitBuf::write_u32_be_at_unchecked: index out of bounds! len is {}, byte_idx is {}",
496      bytes.len(),
497      first_idx + 3,
498    );
499
500    if shift == 0 {
501      unsafe { self.write_u32_be_aligned_at_unchecked(first_idx, v) };
502    } else {
503      let second_idx = first_idx + 1;
504      let third_idx = first_idx + 2;
505      let fourth_idx = first_idx + 3;
506      let fifth_idx = first_idx + 4;
507
508      debug_assert!(
509        fifth_idx < bytes.len(),
510        "BitBuf::write_u32_be_at_unchecked: lookahead index out of bounds! len is {}, lookahead byte_idx is {}",
511        bytes.len(),
512        fifth_idx,
513      );
514
515      let [a, b, c, d] = v.to_be_bytes();
516
517      // first byte, higher part of value
518      unsafe {
519        // mask to keep high bits of the current byte
520        let mask = !0 << (8 - shift);
521        let byte = bytes.get_unchecked(first_idx) & mask;
522        // high bits of the value, shifted down
523        let new = a >> shift;
524        *bytes.get_unchecked_mut(first_idx) = byte | new;
525      }
526
527      // second, third, and fourth byte, middle part of value
528      // all overwritten
529      unsafe {
530        *bytes.get_unchecked_mut(second_idx) = a << (8 - shift) | b >> shift;
531        *bytes.get_unchecked_mut(third_idx) = b << (8 - shift) | c >> shift;
532        *bytes.get_unchecked_mut(fourth_idx) = c << (8 - shift) | d >> shift;
533      }
534
535      // fifth byte, lower part of value
536      unsafe {
537        // mask to keep low bits of the current byte
538        let mask = !0 >> shift;
539        let byte = bytes.get_unchecked(fifth_idx) & mask;
540        // low bits of the value, shifted up
541        let new = d << (8 - shift);
542        *bytes.get_unchecked_mut(fifth_idx) = byte | new;
543      }
544    }
545
546    self
547  }
548
549  /// Write a [`u32`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
550  ///
551  /// # Safety
552  ///
553  /// * This is UB if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
554  /// * This is UB if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
555  ///
556  /// # Panics
557  ///
558  /// * Panics in debug mode if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
559  /// * Panics in debug mode if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
560  #[inline(always)]
561  pub unsafe fn write_u32_be_unchecked(&mut self, v: u32) -> &mut Self {
562    unsafe { self.write_u32_be_at_unchecked(self.pos(), v) };
563    self.advance_bytes(4);
564    self
565  }
566
567  /// Write a [BE-bit, BE-byte] order [`u32`] at `offset` while performing bound checks
568  ///
569  /// # Errors
570  ///
571  /// * Returns [`Error::OutOfBounds`]
572  ///   * if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
573  ///   * if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
574  #[inline(always)]
575  pub fn try_write_u32_be_at(&mut self, offset: usize, v: u32) -> Result<&mut Self> {
576    let first_idx = offset / 8;
577    let shift = offset % 8;
578
579    let len = self.bytes().len();
580
581    if first_idx + 3 >= len {
582      return Err(Error::OutOfBounds);
583    }
584
585    if shift != 0 && first_idx + 4 >= len {
586      return Err(Error::OutOfBounds);
587    }
588
589    Ok(unsafe { self.write_u32_be_at_unchecked(offset, v) })
590  }
591
592  /// Write a [BE-bit, BE-byte] order [`u32`] while performing bound checks, advancing the internal cursor
593  ///
594  /// # Errors
595  ///
596  /// * Returns [`Error::OutOfBounds`]
597  ///   * if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
598  ///   * if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
599  #[inline(always)]
600  pub fn try_write_u32_be(&mut self, v: u32) -> Result<&mut Self> {
601    self.try_write_u32_be_at(self.pos(), v)?;
602    self.advance_bytes(4);
603    Ok(self)
604  }
605
606  /// Write a [BE-bit, BE-byte] order [`u32`] at `offset`, panicking on out of bounds
607  ///
608  /// # Panics
609  ///
610  /// * Panics if <code>(offset / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
611  /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
612  #[inline(always)]
613  pub fn write_u32_be_at(&mut self, offset: usize, v: u32) -> &mut Self {
614    self
615      .try_write_u32_be_at(offset, v)
616      .expect("BitBuf::write_u32_be_at out of bounds")
617  }
618
619  /// Write a [BE-bit, BE-byte] order [`u32`], panicking on out of bounds, advancing the internal cursor
620  ///
621  /// # Panics
622  ///
623  /// * Panics if <code>(self.pos() / 8) + 3 >= [`self.bytes().len()`][Self::bytes]</code>
624  /// * Panics if <code>(self.pos() % 8 != 0) && (self.pos() / 8) + 4 >= [`self.bytes().len()`][Self::bytes]</code>
625  #[inline(always)]
626  pub fn write_u32_be(&mut self, v: u32) -> &mut Self {
627    self
628      .try_write_u32_be(v)
629      .expect("BitBuf::write_u32_be out of bounds")
630  }
631}
632
633pub trait Write: Sized {
634  unsafe fn write_be_aligned_at_unchecked<S: StorageMut>(
635    buf: &mut BitBuf<S>,
636    byte_offset: usize,
637    v: Self,
638  ) -> &mut BitBuf<S>;
639
640  unsafe fn write_be_aligned_unchecked<S: StorageMut>(
641    buf: &mut BitBuf<S>,
642    v: Self,
643  ) -> &mut BitBuf<S>;
644
645  unsafe fn write_be_at_unchecked<S: StorageMut>(
646    buf: &mut BitBuf<S>,
647    offset: usize,
648    v: Self,
649  ) -> &mut BitBuf<S>;
650
651  unsafe fn write_be_unchecked<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S>;
652
653  fn try_write_be_at<S: StorageMut>(
654    buf: &mut BitBuf<S>,
655    offset: usize,
656    v: Self,
657  ) -> Result<&mut BitBuf<S>>;
658
659  fn try_write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>>;
660
661  fn write_be_at<S: StorageMut>(buf: &mut BitBuf<S>, offset: usize, v: Self) -> &mut BitBuf<S>;
662
663  fn write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S>;
664}
665
666impl Write for u8 {
667  #[inline(always)]
668  unsafe fn write_be_aligned_at_unchecked<S: StorageMut>(
669    buf: &mut BitBuf<S>,
670    byte_offset: usize,
671    v: Self,
672  ) -> &mut BitBuf<S> {
673    unsafe { buf.write_u8_be_aligned_at_unchecked(byte_offset, v) }
674  }
675
676  #[inline(always)]
677  unsafe fn write_be_aligned_unchecked<S: StorageMut>(
678    buf: &mut BitBuf<S>,
679    v: Self,
680  ) -> &mut BitBuf<S> {
681    unsafe { buf.write_u8_be_aligned_unchecked(v) }
682  }
683
684  #[inline(always)]
685  unsafe fn write_be_at_unchecked<S: StorageMut>(
686    buf: &mut BitBuf<S>,
687    offset: usize,
688    v: Self,
689  ) -> &mut BitBuf<S> {
690    unsafe { buf.write_u8_be_at_unchecked(offset, v) }
691  }
692
693  #[inline(always)]
694  unsafe fn write_be_unchecked<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
695    unsafe { buf.write_u8_be_unchecked(v) }
696  }
697
698  #[inline(always)]
699  fn try_write_be_at<S: StorageMut>(
700    buf: &mut BitBuf<S>,
701    offset: usize,
702    v: Self,
703  ) -> Result<&mut BitBuf<S>> {
704    buf.try_write_u8_be_at(offset, v)
705  }
706
707  #[inline(always)]
708  fn try_write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>> {
709    buf.try_write_u8_be(v)
710  }
711
712  #[inline(always)]
713  fn write_be_at<S: StorageMut>(buf: &mut BitBuf<S>, offset: usize, v: Self) -> &mut BitBuf<S> {
714    buf.write_u8_be_at(offset, v)
715  }
716
717  #[inline(always)]
718  fn write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
719    buf.write_u8_be(v)
720  }
721}
722
723impl Write for u16 {
724  #[inline(always)]
725  unsafe fn write_be_aligned_at_unchecked<S: StorageMut>(
726    buf: &mut BitBuf<S>,
727    byte_offset: usize,
728    v: Self,
729  ) -> &mut BitBuf<S> {
730    unsafe { buf.write_u16_be_aligned_at_unchecked(byte_offset, v) }
731  }
732
733  #[inline(always)]
734  unsafe fn write_be_aligned_unchecked<S: StorageMut>(
735    buf: &mut BitBuf<S>,
736    v: Self,
737  ) -> &mut BitBuf<S> {
738    unsafe { buf.write_u16_be_aligned_unchecked(v) }
739  }
740
741  #[inline(always)]
742  unsafe fn write_be_at_unchecked<S: StorageMut>(
743    buf: &mut BitBuf<S>,
744    offset: usize,
745    v: Self,
746  ) -> &mut BitBuf<S> {
747    unsafe { buf.write_u16_be_at_unchecked(offset, v) }
748  }
749
750  #[inline(always)]
751  unsafe fn write_be_unchecked<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
752    unsafe { buf.write_u16_be_unchecked(v) }
753  }
754
755  #[inline(always)]
756  fn try_write_be_at<S: StorageMut>(
757    buf: &mut BitBuf<S>,
758    offset: usize,
759    v: Self,
760  ) -> Result<&mut BitBuf<S>> {
761    buf.try_write_u16_be_at(offset, v)
762  }
763
764  #[inline(always)]
765  fn try_write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>> {
766    buf.try_write_u16_be(v)
767  }
768
769  #[inline(always)]
770  fn write_be_at<S: StorageMut>(buf: &mut BitBuf<S>, offset: usize, v: Self) -> &mut BitBuf<S> {
771    buf.write_u16_be_at(offset, v)
772  }
773
774  #[inline(always)]
775  fn write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
776    buf.write_u16_be(v)
777  }
778}
779
780impl Write for u32 {
781  #[inline(always)]
782  unsafe fn write_be_aligned_at_unchecked<S: StorageMut>(
783    buf: &mut BitBuf<S>,
784    byte_offset: usize,
785    v: Self,
786  ) -> &mut BitBuf<S> {
787    unsafe { buf.write_u32_be_aligned_at_unchecked(byte_offset, v) }
788  }
789
790  #[inline(always)]
791  unsafe fn write_be_aligned_unchecked<S: StorageMut>(
792    buf: &mut BitBuf<S>,
793    v: Self,
794  ) -> &mut BitBuf<S> {
795    unsafe { buf.write_u32_be_aligned_unchecked(v) }
796  }
797
798  #[inline(always)]
799  unsafe fn write_be_at_unchecked<S: StorageMut>(
800    buf: &mut BitBuf<S>,
801    offset: usize,
802    v: Self,
803  ) -> &mut BitBuf<S> {
804    unsafe { buf.write_u32_be_at_unchecked(offset, v) }
805  }
806
807  #[inline(always)]
808  unsafe fn write_be_unchecked<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
809    unsafe { buf.write_u32_be_unchecked(v) }
810  }
811
812  #[inline(always)]
813  fn try_write_be_at<S: StorageMut>(
814    buf: &mut BitBuf<S>,
815    offset: usize,
816    v: Self,
817  ) -> Result<&mut BitBuf<S>> {
818    buf.try_write_u32_be_at(offset, v)
819  }
820
821  #[inline(always)]
822  fn try_write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> Result<&mut BitBuf<S>> {
823    buf.try_write_u32_be(v)
824  }
825
826  #[inline(always)]
827  fn write_be_at<S: StorageMut>(buf: &mut BitBuf<S>, offset: usize, v: Self) -> &mut BitBuf<S> {
828    buf.write_u32_be_at(offset, v)
829  }
830
831  #[inline(always)]
832  fn write_be<S: StorageMut>(buf: &mut BitBuf<S>, v: Self) -> &mut BitBuf<S> {
833    buf.write_u32_be(v)
834  }
835}
836
837impl<S: StorageMut> BitBuf<S> {
838  /// Write a [BE-bit, BE-byte] order type `T` at `byte_offset` without performing bound checks
839  ///
840  /// # Safety
841  ///
842  /// All semantics of the corresponding function for the type apply
843  ///
844  /// # Panics
845  ///
846  /// All semantics of the corresponding function for the type apply
847  #[inline(always)]
848  pub unsafe fn write_be_aligned_at_unchecked<T: Write>(
849    &mut self,
850    byte_offset: usize,
851    v: T,
852  ) -> &mut Self {
853    unsafe { T::write_be_aligned_at_unchecked(self, byte_offset, v) }
854  }
855
856  /// Write a [BE-bit, BE-byte] order type `T` without performing bound checks, advancing the internal cursor
857  ///
858  /// # Safety
859  ///
860  /// All semantics of the corresponding function for the type apply
861  ///
862  /// # Panics
863  ///
864  /// All semantics of the corresponding function for the type apply
865  #[inline(always)]
866  pub unsafe fn write_be_aligned_unchecked<T: Write>(&mut self, v: T) -> &mut Self {
867    unsafe { T::write_be_aligned_unchecked(self, v) }
868  }
869
870  /// Write a [BE-bit, BE-byte] order type `T` at `offset` without performing bound checks
871  ///
872  /// # Safety
873  ///
874  /// All semantics of the corresponding function for the type apply
875  ///
876  /// # Panics
877  ///
878  /// All semantics of the corresponding function for the type apply
879  #[inline(always)]
880  pub unsafe fn write_be_at_unchecked<T: Write>(&mut self, offset: usize, v: T) -> &mut Self {
881    unsafe { T::write_be_at_unchecked(self, offset, v) }
882  }
883
884  /// Write a [BE-bit, BE-byte] order type `T` without performing bound checks, advancing the internal cursor
885  ///
886  /// # Safety
887  ///
888  /// All semantics of the corresponding function for the type apply
889  ///
890  /// # Panics
891  ///
892  /// All semantics of the corresponding function for the type apply
893  #[inline(always)]
894  pub unsafe fn write_be_unchecked<T: Write>(&mut self, v: T) -> &mut Self {
895    unsafe { T::write_be_unchecked(self, v) }
896  }
897
898  /// Write a [BE-bit, BE-byte] order type `T` at `offset` while performing bound checks
899  ///
900  /// # Errors
901  ///
902  /// All semantics of the corresponding function for the type apply
903  #[inline(always)]
904  pub fn try_write_be_at<T: Write>(&mut self, offset: usize, v: T) -> Result<&mut Self> {
905    T::try_write_be_at(self, offset, v)
906  }
907
908  /// Write a [BE-bit, BE-byte] order type `T` while performing bound checks, advancing the internal cursor
909  ///
910  /// # Errors
911  ///
912  /// All semantics of the corresponding function for the type apply
913  #[inline(always)]
914  pub fn try_write_be<T: Write>(&mut self, v: T) -> Result<&mut Self> {
915    T::try_write_be(self, v)
916  }
917
918  /// Write a [BE-bit, BE-byte] order type `T` at `offset`, panicking on out of bounds
919  ///
920  /// # Panics
921  ///
922  /// All semantics of the corresponding function for the type apply
923  #[inline(always)]
924  #[must_use]
925  pub fn write_be_at<T: Write>(&mut self, offset: usize, v: T) -> &mut Self {
926    T::write_be_at(self, offset, v)
927  }
928
929  /// Write a [BE-bit, BE-byte] order type `T`, panicking on out of bounds, advancing the internal cursor
930  ///
931  /// # Panics
932  ///
933  /// All semantics of the corresponding function for the type apply
934  #[inline(always)]
935  #[must_use]
936  pub fn write_be<T: Write>(&mut self, v: T) -> &mut Self {
937    T::write_be(self, v)
938  }
939}