to_str/
buffer.rs

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