to_str/
lib.rs

1//! `no_std` friendly interface for conversion to str
2//!
3//! ```
4//! type Buffer = to_str::Buffer64;
5//!
6//! let mut buf = String::new();
7//! let _ = buf.push_str(Buffer::fmt(5usize).as_str());
8//! assert_eq!(buf, "5");
9//!
10//! buf.push_str(Buffer::fmt(0usize).as_str());
11//! assert_eq!(buf, "50");
12//! buf.push_str(Buffer::fmt(&5usize).as_str());
13//! assert_eq!(buf, "505");
14//! buf.push_str(Buffer::fmt(&mut 0usize).as_str());
15//! assert_eq!(buf, "5050");
16//! ```
17
18#![warn(missing_docs)]
19#![allow(clippy::style)]
20#![no_std]
21
22mod buffer;
23mod numeric;
24
25pub use buffer::Buffer;
26
27///Alias to buffer that can be used to write `8` bit integers
28pub type Buffer8 = Buffer<{i8::TEXT_SIZE}>;
29///Alias to buffer that can be used to write `16` bit integers
30pub type Buffer16 = Buffer<{i16::TEXT_SIZE}>;
31///Alias to buffer that can be used to write `32` bit integers
32pub type Buffer32 = Buffer<{i32::TEXT_SIZE}>;
33///Alias to buffer that can be used to write `64` bit integers
34pub type Buffer64 = Buffer<{i64::TEXT_SIZE}>;
35///Alias to buffer that can be used to write `isize` bit integers
36pub type BufferSized = Buffer<{isize::TEXT_SIZE}>;
37///Alias to buffer that can be used to write `128` bit integers
38pub type Buffer128 = Buffer<{i128::TEXT_SIZE}>;
39
40///Describes conversion to string
41///
42///This trait is unsafe due to following requirements:
43///
44///- Implementation must never read buffer, unless it was already written by it;
45///- It writes from the end of buffer (necessary only when you use `Buffer`).
46pub unsafe trait ToStr {
47    ///Max size in bytes to hold the string
48    ///
49    ///Implementation MUST guarantee that this size of buffer is enough to fit any possible textual
50    ///representation
51    const TEXT_SIZE: usize;
52
53    ///Writes textual representation to the buffer
54    ///
55    ///Returns `str` stored in the provided `buffer`
56    ///
57    ///Can panic, if buffer is not sufficient.
58    ///Or write only partially
59    ///
60    ///Implementation is allowed to write any part of the buffer.
61    ///It is not allowed to read it, unless it was written already.
62    ///
63    ///# Safety:
64    ///
65    ///Debug builds must never invoke UB when calling this function.
66    ///
67    ///UB in release mode is fine if one wants to write efficient code.
68    fn to_str<'a>(&self, buffer: &'a mut [u8]) -> &'a str;
69
70    #[inline]
71    ///Performs textual conversion by writing to the buffer, if possible.
72    ///
73    ///If not possible MUST return `None`
74    ///
75    ///By default returns `None` if buffer size is below `TEXT_SIZE`
76    ///Otherwise calls `to_str()` while passing buffer as it is
77    fn to_str_if<'a>(&self, buffer: &'a mut [u8]) -> Option<&'a str> {
78        if buffer.len() < Self::TEXT_SIZE {
79            None
80        } else {
81            Some(self.to_str(buffer))
82        }
83    }
84}
85
86unsafe impl<T: ?Sized + ToStr> ToStr for &T {
87    const TEXT_SIZE: usize = T::TEXT_SIZE;
88
89    #[inline(always)]
90    fn to_str<'b>(&self, buffer: &'b mut [u8]) -> &'b str {
91        (&**self).to_str(buffer)
92    }
93}
94
95unsafe impl<T: ?Sized + ToStr> ToStr for &mut T {
96    const TEXT_SIZE: usize = T::TEXT_SIZE;
97
98    #[inline(always)]
99    fn to_str<'b>(&self, buffer: &'b mut [u8]) -> &'b str {
100        (&**self).to_str(buffer)
101    }
102}