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_full_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_full_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_full_unchecked(&mut self, v: u8) -> &mut Self {
45 debug_assert!(
46 self.is_aligned(),
47 "BitBuf::write_u8_be_aligned_full_unchecked called at unaligned bit position: {}",
48 self.pos(),
49 );
50
51 unsafe { self.write_u8_be_aligned_full_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_full_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_full_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_full_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_full_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 BE-bit-order [`u8`] at `offset` while performing bound checks
118 ///
119 /// # Errors
120 ///
121 /// * Returns [`Error::OutOfBounds`]
122 /// * if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
123 /// * if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
124 #[inline(always)]
125 pub fn try_write_u8_be_full_at(&mut self, offset: usize, v: u8) -> Result<&mut Self> {
126 let byte_idx = offset / 8;
127 let shift = offset % 8;
128
129 let len = self.bytes().len();
130
131 if byte_idx >= len {
132 return Err(Error::OutOfBounds);
133 }
134
135 if shift != 0 && byte_idx + 1 >= len {
136 return Err(Error::OutOfBounds);
137 }
138
139 Ok(unsafe { self.write_u8_be_full_at_unchecked(offset, v) })
140 }
141
142 /// Write a BE-bit-order [`u8`] at `offset`, panicking on out of bounds
143 ///
144 /// # Panics
145 ///
146 /// * Panics if <code>(offset / 8) >= [`self.bytes().len()`][Self::bytes]</code>
147 /// * Panics if <code>(offset % 8 != 0) && (offset / 8) + 1 >= [`self.bytes().len()`][Self::bytes]</code>
148 #[inline(always)]
149 pub fn write_u8_be_full_at(&mut self, offset: usize, v: u8) -> &mut Self {
150 self
151 .try_write_u8_be_full_at(offset, v)
152 .expect("BitBuf::write_u8_be_full_at out of bounds")
153 }
154}