1use core::fmt;
7use core::mem::MaybeUninit;
8use core::ops::{Deref, DerefMut};
9use core::ptr;
10
11use crate::alloc::Vec;
12use crate::writer::Writer;
13use crate::Context;
14
15#[non_exhaustive]
17pub(crate) struct CapacityError;
18
19pub struct FixedBytes<const N: usize> {
22 data: [MaybeUninit<u8>; N],
24 init: usize,
26}
27
28impl<const N: usize> FixedBytes<N> {
29 #[inline]
31 pub const fn new() -> Self {
32 Self {
33 data: unsafe { MaybeUninit::<[MaybeUninit<u8>; N]>::uninit().assume_init() },
35 init: 0,
36 }
37 }
38
39 pub fn with_capacity(capacity: usize) -> Self {
41 assert!(
42 capacity < N,
43 "Requested capacity {capacity} is larger than {N}"
44 );
45 Self::new()
46 }
47
48 #[inline]
50 pub const fn len(&self) -> usize {
51 self.init
52 }
53
54 #[inline]
56 pub const fn is_empty(&self) -> bool {
57 self.init == 0
58 }
59
60 #[inline]
62 pub fn clear(&mut self) {
63 self.init = 0;
64 }
65
66 #[inline]
68 pub const fn remaining(&self) -> usize {
69 N.saturating_sub(self.init)
70 }
71
72 #[inline]
74 pub fn into_bytes(self) -> Option<[u8; N]> {
75 if self.init == N {
76 unsafe { Some((&self.data as *const _ as *const [u8; N]).read()) }
82 } else {
83 None
84 }
85 }
86
87 #[inline]
89 pub fn as_slice(&self) -> &[u8] {
90 if self.init == 0 {
91 return &[];
92 }
93
94 unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.init) }
97 }
98
99 #[inline]
101 pub fn as_mut_slice(&mut self) -> &mut [u8] {
102 if self.init == 0 {
103 return &mut [];
104 }
105
106 unsafe { core::slice::from_raw_parts_mut(self.data.as_mut_ptr().cast(), self.init) }
109 }
110
111 #[inline]
113 pub fn push(&mut self, value: u8) -> bool {
114 if N.saturating_sub(self.init) == 0 {
115 return false;
116 }
117
118 unsafe {
119 self.data
120 .as_mut_ptr()
121 .cast::<u8>()
122 .add(self.init)
123 .write(value)
124 }
125
126 self.init += 1;
127 true
128 }
129
130 #[inline]
132 pub fn extend_from_slice(&mut self, source: &[u8]) -> bool {
133 if source.len() > N.saturating_sub(self.init) {
134 return false;
135 }
136
137 unsafe {
138 let dst = (self.data.as_mut_ptr() as *mut u8).add(self.init);
139 ptr::copy_nonoverlapping(source.as_ptr(), dst, source.len());
140 }
141
142 self.init = self.init.wrapping_add(source.len());
143 true
144 }
145
146 #[inline]
148 pub fn write_bytes<C>(&mut self, cx: &C, source: &[u8]) -> Result<(), C::Error>
149 where
150 C: ?Sized + Context,
151 {
152 if !self.extend_from_slice(source) {
153 return Err(cx.message(FixedBytesOverflow {
154 at: self.init,
155 additional: source.len(),
156 capacity: N,
157 }));
158 }
159
160 Ok(())
161 }
162}
163
164impl<const N: usize> Deref for FixedBytes<N> {
165 type Target = [u8];
166
167 #[inline]
168 fn deref(&self) -> &Self::Target {
169 self.as_slice()
170 }
171}
172
173impl<const N: usize> DerefMut for FixedBytes<N> {
174 #[inline]
175 fn deref_mut(&mut self) -> &mut Self::Target {
176 self.as_mut_slice()
177 }
178}
179
180impl<const N: usize> Default for FixedBytes<N> {
181 #[inline]
182 fn default() -> Self {
183 Self::new()
184 }
185}
186
187impl<const N: usize> Writer for FixedBytes<N> {
188 type Mut<'this> = &'this mut Self where Self: 'this;
189
190 #[inline]
191 fn borrow_mut(&mut self) -> Self::Mut<'_> {
192 self
193 }
194
195 #[inline]
196 fn extend<C>(&mut self, cx: &C, buffer: Vec<'_, u8, C::Allocator>) -> Result<(), C::Error>
197 where
198 C: ?Sized + Context,
199 {
200 self.write_bytes(cx, buffer.as_slice())
202 }
203
204 #[inline]
205 fn write_bytes<C>(&mut self, cx: &C, bytes: &[u8]) -> Result<(), C::Error>
206 where
207 C: ?Sized + Context,
208 {
209 FixedBytes::write_bytes(self, cx, bytes)?;
210 cx.advance(bytes.len());
211 Ok(())
212 }
213}
214
215#[derive(Debug)]
218#[allow(missing_docs)]
219#[non_exhaustive]
220pub(crate) struct FixedBytesOverflow {
221 at: usize,
222 additional: usize,
223 capacity: usize,
224}
225
226impl fmt::Display for FixedBytesOverflow {
227 #[inline]
228 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
229 let FixedBytesOverflow {
230 at,
231 additional,
232 capacity,
233 } = self;
234
235 write!(
236 f,
237 "Tried to write {additional} bytes at {at} with capacity {capacity}"
238 )
239 }
240}