to_str/
buffer.rs

1use core::mem;
2
3///Static buffer to hold written text.
4///
5///Implementation of `ToStr` must write it from the end.
6pub struct Buffer<T> {
7    inner: core::mem::MaybeUninit<T>,
8    offset: u8,
9}
10
11impl<S: Sized> Buffer<S> {
12    #[inline]
13    ///Creates new instance
14    pub const fn new() -> Self {
15        Self {
16            inner: core::mem::MaybeUninit::uninit(),
17            offset: 0,
18        }
19    }
20
21    #[inline]
22    ///Returns pointer  to the beginning of underlying buffer
23    pub const fn as_ptr(&self) -> *const u8 {
24        &self.inner as *const _ as *const u8
25    }
26
27    #[inline]
28    ///Returns pointer  to the beginning of underlying buffer
29    const fn as_mut_ptr(&mut self) -> *mut u8 {
30        self.inner.as_mut_ptr() as _
31    }
32
33    #[inline]
34    ///Returns buffer overall capacity.
35    pub const fn capacity() -> usize {
36        mem::size_of::<S>()
37    }
38
39    #[inline(always)]
40    ///Access str from underlying storage
41    ///
42    ///Returns empty if nothing has been written into buffer yet.
43    pub fn as_str(&self) -> &str {
44        unsafe {
45            let slice = core::slice::from_raw_parts(self.as_ptr().offset(self.offset as isize), Self::capacity() - self.offset as usize);
46            core::str::from_utf8_unchecked(slice)
47        }
48    }
49
50    #[inline]
51    ///Formats value into buffer, returning text.
52    ///
53    ///Buffer remembers the write, therefore `as_str()` will return the same text as last
54    ///`write`
55    pub fn write<T: crate::ToStr>(&mut self, val: T) -> &str {
56        self.offset = (Self::capacity() - self.format(val).len()) as u8;
57        self.as_str()
58    }
59
60    #[inline(always)]
61    ///Formats value into buffer, returning text.
62    ///
63    ///Buffer remains unaware of modifications
64    pub fn format<T: crate::ToStr>(&mut self, val: T) -> &str {
65        //Yes, because we cannot assert statically in generics, we must go through these hacks
66        //We can add this assertion once panic will be allowed inside const fn
67        debug_assert!(Self::capacity() <= u8::max_value() as usize);
68        debug_assert!(T::TEXT_SIZE <= Self::capacity());
69
70        val.to_str(unsafe {
71            &mut *core::ptr::slice_from_raw_parts_mut(self.as_mut_ptr() as *mut u8, Self::capacity())
72        })
73    }
74
75    #[inline(always)]
76    ///Creates new instance with formatted value.
77    pub fn fmt<T: crate::ToStr>(val: T) -> Self {
78        let mut this = Self::new();
79        this.write(val);
80        this
81    }
82}
83
84impl<S: Sized> AsRef<str> for Buffer<S> {
85    #[inline(always)]
86    fn as_ref(&self) -> &str {
87        self.as_str()
88    }
89}
90
91impl<S: Sized> core::fmt::Display for Buffer<S> {
92    #[inline(always)]
93    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
94        f.write_str(self.as_str())
95    }
96}
97
98impl<S: Sized> core::fmt::Debug for Buffer<S> {
99    #[inline(always)]
100    fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
101        f.write_str(self.as_str())
102    }
103}