1use std::mem::MaybeUninit;
32
33pub struct MemBufStr<'a> {
36 len: &'a mut usize,
37 buffer: &'a mut [MaybeUninit<u8>],
38}
39
40impl<'a> MemBufStr<'a> {
41 pub unsafe fn wrap_uninit(
49 len: &'a mut usize,
50 buffer: &'a mut [MaybeUninit<u8>],
51 ) -> MemBufStr<'a> {
52 MemBufStr { buffer, len }
53 }
54
55 pub unsafe fn wrap(len: &'a mut usize, buffer: &'a mut [u8]) -> MemBufStr<'a> {
63 MemBufStr {
64 #[allow(clippy::missing_transmute_annotations)]
65 buffer: std::mem::transmute(buffer),
66 len,
67 }
68 }
69
70 #[allow(clippy::missing_transmute_annotations)]
73 pub fn str(&self) -> &str {
74 unsafe { std::str::from_utf8_unchecked(std::mem::transmute(&self.buffer[..*self.len])) }
75 }
76
77 #[allow(clippy::missing_transmute_annotations)]
95 pub unsafe fn write(&mut self, buf: &[u8]) -> usize {
96 let len = utf8_max(buf, self.buffer.len() - *self.len);
97 unsafe {
98 std::ptr::copy_nonoverlapping(
99 buf.as_ptr(),
100 std::mem::transmute(self.buffer.as_mut_ptr().add(*self.len)),
101 len,
102 );
103 }
104 *self.len += len;
105 len
106 }
107}
108
109impl std::fmt::Write for MemBufStr<'_> {
110 fn write_str(&mut self, value: &str) -> std::fmt::Result {
111 unsafe { self.write(value.as_bytes()) };
112 Ok(())
113 }
114}
115
116#[derive(Clone, Debug)]
118pub struct FixedBufStr<const N: usize> {
119 len: usize,
120 buffer: [MaybeUninit<u8>; N],
121}
122
123impl<const N: usize> Default for FixedBufStr<N> {
124 fn default() -> Self {
125 Self::new()
126 }
127}
128
129#[inline(always)]
135fn utf8_max(buf: &[u8], max: usize) -> usize {
136 let buf_len = buf.len();
137 if buf_len <= max {
138 buf_len
139 } else if max == 0 {
140 0
141 } else if unsafe { buf.get_unchecked(max.unchecked_sub(1)) } & 0x80 == 0x00 {
142 max
143 } else {
144 let start = unsafe { max.unchecked_sub(1) };
145 let mut i = start;
146 unsafe {
147 while buf.get_unchecked(i) & 0xC0 == 0x80 {
148 i = i.unchecked_sub(1);
149 }
150 let n = start.unchecked_sub(i);
151 if (buf.get_unchecked(i) & 0xF0 == 0xF0 && n == 4)
152 || (buf.get_unchecked(i) & 0xE0 == 0xE0 && n == 3)
153 || (buf.get_unchecked(i) & 0xC0 == 0xC0 && n == 2)
154 {
155 max
156 } else {
157 i
158 }
159 }
160 }
161}
162
163impl<const N: usize> FixedBufStr<N> {
164 pub fn new() -> FixedBufStr<N> {
166 FixedBufStr {
167 buffer: unsafe { MaybeUninit::uninit().assume_init() },
168 len: 0,
169 }
170 }
171
172 #[allow(clippy::missing_transmute_annotations)]
175 pub fn str(&self) -> &str {
176 unsafe { std::str::from_utf8_unchecked(std::mem::transmute(&self.buffer[..self.len as _])) }
177 }
178
179 #[allow(clippy::missing_transmute_annotations)]
182 #[allow(clippy::should_implement_trait)]
184 pub fn from_str(value: &str) -> Self {
185 let mut buffer = FixedBufStr::new();
186 let len = utf8_max(value.as_bytes(), N);
187 unsafe {
188 std::ptr::copy_nonoverlapping(
189 value.as_ptr(),
190 std::mem::transmute(buffer.buffer.as_mut_ptr()),
191 len,
192 );
193 }
194 buffer.len = len as _;
195 buffer
196 }
197
198 #[allow(clippy::missing_transmute_annotations)]
216 pub unsafe fn write(&mut self, buf: &[u8]) -> usize {
217 let len = utf8_max(buf, N - self.len);
218 unsafe {
219 std::ptr::copy_nonoverlapping(
220 buf.as_ptr(),
221 std::mem::transmute(self.buffer.as_mut_ptr().add(self.len)),
222 len,
223 );
224 }
225 self.len += len;
226 len
227 }
228
229 pub fn clear(&mut self) {
231 self.len = 0;
232 }
233}
234
235impl<const N: usize> std::fmt::Write for FixedBufStr<N> {
236 fn write_str(&mut self, value: &str) -> std::fmt::Result {
237 unsafe { self.write(value.as_bytes()) };
238 Ok(())
239 }
240}
241
242pub struct IoToFmt<W: std::fmt::Write>(W);
247
248impl<W: std::fmt::Write> IoToFmt<W> {
249 pub fn new(w: W) -> Self {
257 Self(w)
258 }
259
260 pub fn into_inner(self) -> W {
262 self.0
263 }
264}
265
266impl<W: std::fmt::Write> std::io::Write for IoToFmt<W> {
267 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
268 let str = std::str::from_utf8(buf)
269 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))?;
270 self.0
271 .write_str(str)
272 .map(|_| str.len())
273 .map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
274 }
275
276 fn flush(&mut self) -> std::io::Result<()> {
277 Ok(())
278 }
279}
280
281#[cfg(test)]
282mod tests {
283 use crate::format::{FixedBufStr, MemBufStr};
284 use std::fmt::Write;
285 use std::mem::MaybeUninit;
286
287 #[test]
288 fn basic() {
289 let mut msg: FixedBufStr<64> = FixedBufStr::new();
290 let _ = write!(msg, "this");
291 let _ = write!(msg, " is");
292 let _ = write!(msg, " a");
293 let _ = write!(msg, " test");
294 assert_eq!(msg.str(), "this is a test");
295 }
296
297 #[test]
298 fn basic_mem() {
299 let mut buf: [MaybeUninit<u8>; 64] = unsafe { MaybeUninit::uninit().assume_init() };
300 let mut len = 0;
301 let mut msg = unsafe { MemBufStr::wrap_uninit(&mut len, &mut buf) };
302 let _ = write!(msg, "this");
303 let _ = write!(msg, " is");
304 let _ = write!(msg, " a");
305 let _ = write!(msg, " test");
306 assert_eq!(msg.str(), "this is a test");
307 }
308
309 #[test]
310 fn truncate_ascii() {
311 let mut msg: FixedBufStr<4> = FixedBufStr::new();
312 let _ = write!(msg, "this");
313 let _ = write!(msg, " is");
314 let _ = write!(msg, " a");
315 let _ = write!(msg, " test");
316 assert_eq!(msg.str().len(), 4);
317 assert_eq!(msg.str(), "this");
318 }
319
320 #[test]
321 fn truncate_ascii_mem() {
322 let mut buf = [0; 4];
323 let mut len = 0;
324 let mut msg = unsafe { MemBufStr::wrap(&mut len, &mut buf) };
325 let _ = write!(msg, "this");
326 let _ = write!(msg, " is");
327 let _ = write!(msg, " a");
328 let _ = write!(msg, " test");
329 assert_eq!(msg.str().len(), 4);
330 assert_eq!(msg.str(), "this");
331 }
332
333 #[test]
334 fn truncate_utf8_exact() {
335 let mut msg: FixedBufStr<3> = FixedBufStr::new();
336 let _ = write!(msg, "我");
337 assert_eq!(msg.str().len(), 3);
338 assert_eq!(msg.str(), "我");
339 }
340
341 #[test]
342 fn truncate_utf8_exact_mem() {
343 let mut buf = [0; 3];
344 let mut len = 0;
345 let mut msg = unsafe { MemBufStr::wrap(&mut len, &mut buf) };
346 let _ = write!(msg, "我");
347 assert_eq!(msg.str().len(), 3);
348 assert_eq!(msg.str(), "我");
349 }
350
351 #[test]
352 fn truncate_utf8_exact2() {
353 let mut msg: FixedBufStr<6> = FixedBufStr::new();
354 let _ = write!(msg, "我是");
355 assert_eq!(msg.str().len(), 6);
356 assert_eq!(msg.str(), "我是");
357 }
358
359 #[test]
360 fn truncate_utf8_exact2_mem() {
361 let mut buf = [0; 6];
362 let mut len = 0;
363 let mut msg = unsafe { MemBufStr::wrap(&mut len, &mut buf) };
364 let _ = write!(msg, "我是");
365 assert_eq!(msg.str().len(), 6);
366 assert_eq!(msg.str(), "我是");
367 }
368
369 #[test]
370 fn truncate_utf8_exact3() {
371 let mut msg: FixedBufStr<6> = FixedBufStr::new();
372 let _ = write!(msg, "我abcd");
373 assert_eq!(msg.str().len(), 6);
374 assert_eq!(msg.str(), "我abc");
375 }
376
377 #[test]
378 fn truncate_utf8_exact3_mem() {
379 let mut buf = [0; 6];
380 let mut len = 0;
381 let mut msg = unsafe { MemBufStr::wrap(&mut len, &mut buf) };
382 let _ = write!(msg, "我abcd");
383 assert_eq!(msg.str().len(), 6);
384 assert_eq!(msg.str(), "我abc");
385 }
386
387 #[test]
388 fn truncate_utf8() {
389 let mut msg: FixedBufStr<4> = FixedBufStr::new();
390 let _ = write!(msg, "我是");
391 assert_eq!(msg.str().len(), 3);
392 assert_eq!(msg.str(), "我");
393 }
394
395 #[test]
396 fn truncate_utf8_mem() {
397 let mut buf = [0; 4];
398 let mut len = 0;
399 let mut msg = unsafe { MemBufStr::wrap(&mut len, &mut buf) };
400 let _ = write!(msg, "我是");
401 assert_eq!(msg.str().len(), 3);
402 assert_eq!(msg.str(), "我");
403 }
404}