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
155 /// Write a [`u16`] in [BE-bit, BE-byte] order at `byte_offset` without performing bound checks
156 ///
157 /// # Safety
158 ///
159 /// * This is UB if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
160 ///
161 /// # Panics
162 ///
163 /// * Panics in debug mode if [`byte_offset + 1 >= self.bytes().len()`][Self::bytes]
164 #[inline(always)]
165 pub unsafe fn write_u16_be_aligned_full_at_unchecked(
166 &mut self,
167 byte_offset: usize,
168 v: u16,
169 ) -> &mut Self {
170 let bytes = self.bytes_mut();
171
172 debug_assert!(
173 byte_offset + 1 < bytes.len(),
174 "BitBuf::write_u16_be_aligned_full_at_unchecked: index out of bounds! len is {}, offset is {}",
175 bytes.len(),
176 byte_offset + 1,
177 );
178
179 let [high, low] = v.to_be_bytes();
180
181 unsafe {
182 *bytes.get_unchecked_mut(byte_offset) = high;
183 *bytes.get_unchecked_mut(byte_offset + 1) = low;
184 }
185
186 self
187 }
188
189 /// Write a [`u16`] in [BE-bit, BE-byte] order without performing bound checks, advancing the internal cursor
190 ///
191 /// # Safety
192 ///
193 /// * The internal cursor must be byte-aligned ([`self.is_aligned()`][Self::is_aligned])
194 /// * 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>)
195 ///
196 /// # Panics
197 ///
198 /// * Panics in debug mode if the internal cursor is not byte-aligned ([`!self.is_aligned()`][Self::is_aligned])
199 /// * 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>)
200 #[inline(always)]
201 pub unsafe fn write_u16_be_aligned_full_unchecked(&mut self, v: u16) -> &mut Self {
202 debug_assert!(
203 self.is_aligned(),
204 "BitBuf::write_u16_be_aligned_full_unchecked called at unaligned bit position: {}",
205 self.pos(),
206 );
207
208 unsafe { self.write_u16_be_aligned_full_at_unchecked(self.byte_pos(), v) };
209 self.advance_bytes(2);
210 self
211 }
212}