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
15pub struct FixedBytes<const N: usize> {
18 data: [MaybeUninit<u8>; N],
20 init: usize,
22}
23
24impl<const N: usize> FixedBytes<N> {
25 #[inline]
27 pub const fn new() -> Self {
28 Self {
29 data: unsafe { MaybeUninit::<[MaybeUninit<u8>; N]>::uninit().assume_init() },
31 init: 0,
32 }
33 }
34
35 #[inline]
37 pub fn with_capacity(capacity: usize) -> Self {
38 assert!(
39 capacity < N,
40 "Requested capacity {capacity} is larger than {N}"
41 );
42 Self::new()
43 }
44
45 #[inline]
47 pub const fn len(&self) -> usize {
48 self.init
49 }
50
51 #[inline]
53 pub const fn is_empty(&self) -> bool {
54 self.init == 0
55 }
56
57 #[inline]
59 pub fn clear(&mut self) {
60 self.init = 0;
61 }
62
63 #[inline]
65 pub const fn remaining(&self) -> usize {
66 N.saturating_sub(self.init)
67 }
68
69 #[inline]
71 pub fn into_bytes(self) -> Option<[u8; N]> {
72 if self.init == N {
73 unsafe { Some((&self.data as *const _ as *const [u8; N]).read()) }
79 } else {
80 None
81 }
82 }
83
84 #[inline]
86 pub fn as_slice(&self) -> &[u8] {
87 if self.init == 0 {
88 return &[];
89 }
90
91 unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.init) }
94 }
95
96 #[inline]
98 pub fn as_mut_slice(&mut self) -> &mut [u8] {
99 if self.init == 0 {
100 return &mut [];
101 }
102
103 unsafe { core::slice::from_raw_parts_mut(self.data.as_mut_ptr().cast(), self.init) }
106 }
107
108 #[inline]
110 pub fn push(&mut self, value: u8) -> bool {
111 if N.saturating_sub(self.init) == 0 {
112 return false;
113 }
114
115 unsafe {
116 self.data
117 .as_mut_ptr()
118 .cast::<u8>()
119 .add(self.init)
120 .write(value)
121 }
122
123 self.init += 1;
124 true
125 }
126
127 #[inline]
129 pub fn extend_from_slice(&mut self, source: &[u8]) -> bool {
130 if source.len() > N.saturating_sub(self.init) {
131 return false;
132 }
133
134 unsafe {
135 let dst = (self.data.as_mut_ptr() as *mut u8).add(self.init);
136 ptr::copy_nonoverlapping(source.as_ptr(), dst, source.len());
137 }
138
139 self.init = self.init.wrapping_add(source.len());
140 true
141 }
142
143 #[inline]
145 pub fn write_bytes<C>(&mut self, cx: C, source: &[u8]) -> Result<(), C::Error>
146 where
147 C: Context,
148 {
149 if !self.extend_from_slice(source) {
150 return Err(cx.message(FixedBytesOverflow {
151 at: self.init,
152 additional: source.len(),
153 capacity: N,
154 }));
155 }
156
157 Ok(())
158 }
159}
160
161impl<const N: usize> Deref for FixedBytes<N> {
162 type Target = [u8];
163
164 #[inline]
165 fn deref(&self) -> &Self::Target {
166 self.as_slice()
167 }
168}
169
170impl<const N: usize> DerefMut for FixedBytes<N> {
171 #[inline]
172 fn deref_mut(&mut self) -> &mut Self::Target {
173 self.as_mut_slice()
174 }
175}
176
177impl<const N: usize> Default for FixedBytes<N> {
178 #[inline]
179 fn default() -> Self {
180 Self::new()
181 }
182}
183
184impl<const N: usize> Writer for FixedBytes<N> {
185 type Ok = ();
186 type Mut<'this>
187 = &'this mut Self
188 where
189 Self: 'this;
190
191 #[inline]
192 fn finish<C>(&mut self, _: C) -> Result<Self::Ok, C::Error>
193 where
194 C: Context,
195 {
196 Ok(())
197 }
198
199 #[inline]
200 fn borrow_mut(&mut self) -> Self::Mut<'_> {
201 self
202 }
203
204 #[inline]
205 fn extend<C>(&mut self, cx: C, buffer: Vec<u8, C::Allocator>) -> Result<(), C::Error>
206 where
207 C: Context,
208 {
209 self.write_bytes(cx, buffer.as_slice())
211 }
212
213 #[inline]
214 fn write_bytes<C>(&mut self, cx: C, bytes: &[u8]) -> Result<(), C::Error>
215 where
216 C: Context,
217 {
218 FixedBytes::write_bytes(self, cx, bytes)?;
219 cx.advance(bytes.len());
220 Ok(())
221 }
222}
223
224#[derive(Debug)]
227#[allow(missing_docs)]
228#[non_exhaustive]
229pub(crate) struct FixedBytesOverflow {
230 at: usize,
231 additional: usize,
232 capacity: usize,
233}
234
235impl fmt::Display for FixedBytesOverflow {
236 #[inline]
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 let FixedBytesOverflow {
239 at,
240 additional,
241 capacity,
242 } = self;
243
244 write!(
245 f,
246 "Tried to write {additional} bytes at {at} with capacity {capacity}"
247 )
248 }
249}