Skip to main content

to_str/
buffer.rs

1use crate::{numeric, ToStr};
2use crate::utils::AssertSizeIsLessOrEqualThan;
3
4use core::{fmt, mem};
5
6///Static buffer to hold written text.
7///
8///Implementation of `ToStr` must write it from the end.
9///
10///## Buffer size limit
11///
12///Buffer size cannot be greater than 255.
13///
14///Following code will fail at compile time:
15///
16///### Invalid buffer creation
17///
18///```rust,compile_fail
19///to_str::Buffer::<256>::new();;
20///```
21///
22///### Formatting with buffer overflow
23///
24///```rust,compile_fail
25///to_str::Buffer::<1>::new().format_u8(255);
26///```
27pub struct Buffer<const N: usize> {
28    inner: [core::mem::MaybeUninit<u8>; N],
29    offset: u8,
30}
31
32impl<const N: usize> Buffer<N> {
33    const VALIDATION: () = {
34        assert!(Self::capacity() <= u8::MAX as usize, "Buffer capacity cannot be greater than 255");
35    };
36
37    #[inline]
38    ///Creates new instance
39    pub const fn new() -> Self {
40        let _ = Self::VALIDATION;
41        Self {
42            #[cfg(debug_assertions)]
43            inner: [mem::MaybeUninit::zeroed(); N],
44            #[cfg(not(debug_assertions))]
45            inner: [mem::MaybeUninit::uninit(); N],
46            offset: 0,
47        }
48    }
49
50    #[inline]
51    ///Returns pointer  to the beginning of underlying buffer
52    pub const fn as_ptr(&self) -> *const u8 {
53        self.inner.as_ptr() as _
54    }
55
56    #[inline]
57    ///Returns pointer  to the beginning of underlying buffer
58    const fn as_mut_ptr(&mut self) -> *mut u8 {
59        self.inner.as_mut_ptr() as _
60    }
61
62    #[inline]
63    ///Returns buffer overall capacity.
64    pub const fn capacity() -> usize {
65        N
66    }
67
68    #[inline(always)]
69    const fn as_offset_str(&self, offset: isize) -> &str {
70        unsafe {
71            let slice = core::slice::from_raw_parts(self.as_ptr().offset(offset), Self::capacity() - offset as usize);
72            core::str::from_utf8_unchecked(slice)
73        }
74    }
75
76    #[inline(always)]
77    ///Access str from underlying storage
78    ///
79    ///Returns empty if nothing has been written into buffer yet.
80    pub const fn as_str(&self) -> &str {
81        self.as_offset_str(self.offset as _)
82    }
83
84    #[inline]
85    ///Formats value into buffer, returning text.
86    ///
87    ///Buffer remembers the write, therefore `as_str()` will return the same text as last
88    ///`write`
89    pub fn write<T: ToStr>(&mut self, val: T) -> &str {
90        self.offset = (Self::capacity() - self.format(val).len()) as u8;
91        self.as_str()
92    }
93
94    #[inline(always)]
95    ///Formats value into buffer, returning text.
96    ///
97    ///Buffer remains unaware of modifications
98    pub fn format<T: ToStr>(&mut self, val: T) -> &str {
99        let _ = Self::VALIDATION;
100        assert!(T::TEXT_SIZE <= Self::capacity());
101
102        val.to_str(unsafe {
103            &mut *core::ptr::slice_from_raw_parts_mut(self.as_mut_ptr(), Self::capacity())
104        })
105    }
106    #[inline(always)]
107    ///Creates new instance with formatted value.
108    pub fn fmt<T: crate::ToStr>(val: T) -> Self {
109        let mut this = Self::new();
110        this.write(val);
111        this
112    }
113}
114
115impl<const N: usize> Buffer<N> {
116    #[inline(always)]
117    ///Specialized const format of `u8` value into buffer, returning text.
118    pub const fn format_u8(&mut self, val: u8) -> &str {
119        let _ = AssertSizeIsLessOrEqualThan::<{<u8 as ToStr>::TEXT_SIZE}, N>::RESULT;
120
121        numeric::unsigned::u8(val, &mut self.inner)
122    }
123
124    #[inline(always)]
125    ///Creates new instance with formatted value.
126    pub const fn fmt_u8(val: u8) -> Self {
127        let _ = AssertSizeIsLessOrEqualThan::<{<u8 as ToStr>::TEXT_SIZE}, N>::RESULT;
128
129        let mut this = Self::new();
130        this.offset = (Self::capacity() - numeric::unsigned::u8(val, &mut this.inner).len()) as u8;
131        this
132    }
133
134    #[inline(always)]
135    ///Specialized const format of `u16` value into buffer, returning text.
136    pub const fn format_u16(&mut self, val: u16) -> &str {
137        let _ = AssertSizeIsLessOrEqualThan::<{<u16 as ToStr>::TEXT_SIZE}, N>::RESULT;
138
139        numeric::unsigned::u16(val, &mut self.inner)
140    }
141
142    #[inline(always)]
143    ///Creates new instance with formatted value.
144    pub const fn fmt_u16(val: u16) -> Self {
145        let _ = AssertSizeIsLessOrEqualThan::<{<u16 as ToStr>::TEXT_SIZE}, N>::RESULT;
146
147        let mut this = Self::new();
148        this.offset = (Self::capacity() - numeric::unsigned::u16(val, &mut this.inner).len()) as u8;
149        this
150    }
151
152    #[inline(always)]
153    ///Specialized const format of `u32` value into buffer, returning text.
154    pub const fn format_u32(&mut self, val: u32) -> &str {
155        let _ = AssertSizeIsLessOrEqualThan::<{<u32 as ToStr>::TEXT_SIZE}, N>::RESULT;
156
157        numeric::unsigned::u32(val, &mut self.inner)
158    }
159
160    #[inline(always)]
161    ///Creates new instance with formatted value.
162    pub const fn fmt_u32(val: u32) -> Self {
163        let _ = AssertSizeIsLessOrEqualThan::<{<u32 as ToStr>::TEXT_SIZE}, N>::RESULT;
164
165        let mut this = Self::new();
166        this.offset = (Self::capacity() - numeric::unsigned::u32(val, &mut this.inner).len()) as u8;
167        this
168    }
169
170    #[inline(always)]
171    ///Specialized const format of `u64` value into buffer, returning text.
172    pub const fn format_u64(&mut self, val: u64) -> &str {
173        let _ = AssertSizeIsLessOrEqualThan::<{<u64 as ToStr>::TEXT_SIZE}, N>::RESULT;
174
175        numeric::unsigned::u64(val, &mut self.inner)
176    }
177
178    #[inline(always)]
179    ///Creates new instance with formatted value.
180    pub const fn fmt_u64(val: u64) -> Self {
181        let _ = AssertSizeIsLessOrEqualThan::<{<u64 as ToStr>::TEXT_SIZE}, N>::RESULT;
182
183        let mut this = Self::new();
184        this.offset = (Self::capacity() - numeric::unsigned::u64(val, &mut this.inner).len()) as u8;
185        this
186    }
187
188    #[inline(always)]
189    ///Specialized const format of `usize` value into buffer, returning text.
190    pub const fn format_usize(&mut self, val: usize) -> &str {
191        let _ = AssertSizeIsLessOrEqualThan::<{<usize as ToStr>::TEXT_SIZE}, N>::RESULT;
192
193        numeric::unsigned::usize(val, &mut self.inner)
194    }
195
196    #[inline(always)]
197    ///Creates new instance with formatted value.
198    pub const fn fmt_usize(val: usize) -> Self {
199        let _ = AssertSizeIsLessOrEqualThan::<{<usize as ToStr>::TEXT_SIZE}, N>::RESULT;
200
201        let mut this = Self::new();
202        this.offset = (Self::capacity() - numeric::unsigned::usize(val, &mut this.inner).len()) as u8;
203        this
204    }
205
206    #[inline(always)]
207    ///Specialized const format of `u128` value into buffer, returning text.
208    pub const fn format_u128(&mut self, val: u128) -> &str {
209        let _ = AssertSizeIsLessOrEqualThan::<{<u128 as ToStr>::TEXT_SIZE}, N>::RESULT;
210
211        numeric::unsigned::u128(val, &mut self.inner)
212    }
213
214    #[inline(always)]
215    ///Creates new instance with formatted value.
216    pub const fn fmt_u128(val: u128) -> Self {
217        let _ = AssertSizeIsLessOrEqualThan::<{<u128 as ToStr>::TEXT_SIZE}, N>::RESULT;
218
219        let mut this = Self::new();
220        this.offset = (Self::capacity() - numeric::unsigned::u128(val, &mut this.inner).len()) as u8;
221        this
222    }
223}
224
225impl<const N: usize> Buffer<N> {
226    #[inline(always)]
227    ///Specialized const format of `i8` value into buffer, returning text.
228    pub const fn format_i8(&mut self, val: i8) -> &str {
229        let _ = AssertSizeIsLessOrEqualThan::<{<i8 as ToStr>::TEXT_SIZE}, N>::RESULT;
230
231        numeric::signed::i8(val, &mut self.inner)
232    }
233
234    #[inline(always)]
235    ///Creates new instance with formatted value.
236    pub const fn fmt_i8(val: i8) -> Self {
237        let _ = AssertSizeIsLessOrEqualThan::<{<i8 as ToStr>::TEXT_SIZE}, N>::RESULT;
238
239        let mut this = Self::new();
240        this.offset = (Self::capacity() - numeric::signed::i8(val, &mut this.inner).len()) as u8;
241        this
242    }
243
244    #[inline(always)]
245    ///Specialized const format of `i16` value into buffer, returning text.
246    pub const fn format_i16(&mut self, val: i16) -> &str {
247        let _ = AssertSizeIsLessOrEqualThan::<{<i16 as ToStr>::TEXT_SIZE}, N>::RESULT;
248
249        numeric::signed::i16(val, &mut self.inner)
250    }
251
252    #[inline(always)]
253    ///Creates new instance with formatted value.
254    pub const fn fmt_i16(val: i16) -> Self {
255        let _ = AssertSizeIsLessOrEqualThan::<{<i16 as ToStr>::TEXT_SIZE}, N>::RESULT;
256
257        let mut this = Self::new();
258        this.offset = (Self::capacity() - numeric::signed::i16(val, &mut this.inner).len()) as u8;
259        this
260    }
261
262    #[inline(always)]
263    ///Specialized const format of `i32` value into buffer, returning text.
264    pub const fn format_i32(&mut self, val: i32) -> &str {
265        let _ = AssertSizeIsLessOrEqualThan::<{<i32 as ToStr>::TEXT_SIZE}, N>::RESULT;
266
267        numeric::signed::i32(val, &mut self.inner)
268    }
269
270    #[inline(always)]
271    ///Creates new instance with formatted value.
272    pub const fn fmt_i32(val: i32) -> Self {
273        let _ = AssertSizeIsLessOrEqualThan::<{<i32 as ToStr>::TEXT_SIZE}, N>::RESULT;
274
275        let mut this = Self::new();
276        this.offset = (Self::capacity() - numeric::signed::i32(val, &mut this.inner).len()) as u8;
277        this
278    }
279
280    #[inline(always)]
281    ///Specialized const format of `i64` value into buffer, returning text.
282    pub const fn format_i64(&mut self, val: i64) -> &str {
283        let _ = AssertSizeIsLessOrEqualThan::<{<i64 as ToStr>::TEXT_SIZE}, N>::RESULT;
284
285        numeric::signed::i64(val, &mut self.inner)
286    }
287
288    #[inline(always)]
289    ///Creates new instance with formatted value.
290    pub const fn fmt_i64(val: i64) -> Self {
291        let _ = AssertSizeIsLessOrEqualThan::<{<i64 as ToStr>::TEXT_SIZE}, N>::RESULT;
292
293        let mut this = Self::new();
294        this.offset = (Self::capacity() - numeric::signed::i64(val, &mut this.inner).len()) as u8;
295        this
296    }
297
298    #[inline(always)]
299    ///Specialized const format of `isize` value into buffer, returning text.
300    pub const fn format_isize(&mut self, val: isize) -> &str {
301        let _ = AssertSizeIsLessOrEqualThan::<{<isize as ToStr>::TEXT_SIZE}, N>::RESULT;
302
303        numeric::signed::isize(val, &mut self.inner)
304    }
305
306    #[inline(always)]
307    ///Creates new instance with formatted value.
308    pub const fn fmt_isize(val: isize) -> Self {
309        let _ = AssertSizeIsLessOrEqualThan::<{<isize as ToStr>::TEXT_SIZE}, N>::RESULT;
310
311        let mut this = Self::new();
312        this.offset = (Self::capacity() - numeric::signed::isize(val, &mut this.inner).len()) as u8;
313        this
314    }
315
316    #[inline(always)]
317    ///Specialized const format of `i128` value into buffer, returning text.
318    pub const fn format_i128(&mut self, val: i128) -> &str {
319        let _ = AssertSizeIsLessOrEqualThan::<{<i128 as ToStr>::TEXT_SIZE}, N>::RESULT;
320
321        numeric::signed::i128(val, &mut self.inner)
322    }
323
324    #[inline(always)]
325    ///Creates new instance with formatted value.
326    pub const fn fmt_i128(val: i128) -> Self {
327        let _ = AssertSizeIsLessOrEqualThan::<{<i128 as ToStr>::TEXT_SIZE}, N>::RESULT;
328
329        let mut this = Self::new();
330        this.offset = (Self::capacity() - numeric::signed::i128(val, &mut this.inner).len()) as u8;
331        this
332    }
333}
334
335impl<const N: usize> AsRef<str> for Buffer<N> {
336    #[inline(always)]
337    fn as_ref(&self) -> &str {
338        self.as_str()
339    }
340}
341
342impl<const N: usize> fmt::Display for Buffer<N> {
343    #[inline(always)]
344    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
345        fmt.write_str(self.as_str())
346    }
347}
348
349impl<const N: usize> fmt::Debug for Buffer<N> {
350    #[inline(always)]
351    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
352        fmt::Debug::fmt(self.as_str(), fmt)
353    }
354}