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#![cfg_attr(feature = "cargo-clippy", 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 `128` bit integers
28pub type Buffer128 = Buffer<[u8; i128::TEXT_SIZE]>;
29///Alias to buffer that can be used to write `64` bit integers
30pub type Buffer64 = Buffer<[u8; i64::TEXT_SIZE]>;
31///Alias to buffer that can be used to write `32` bit integers
32pub type Buffer32 = Buffer<[u8; i32::TEXT_SIZE]>;
33///Alias to buffer that can be used to write `isize` bit integers
34pub type BufferSized = Buffer<[u8; isize::TEXT_SIZE]>;
35
36///Describes conversion to string
37///
38///This trait is unsafe due to following requirements:
39///
40///- Implementation must never read buffer, unless it was already written by it;
41///- It writes from the end of buffer (necessary only when you use `Buffer`).
42pub unsafe trait ToStr {
43 ///Max size in bytes to hold the string
44 ///
45 ///Implementation MUST guarantee that this size of buffer is enough to fit any possible textual
46 ///representation
47 const TEXT_SIZE: usize;
48
49 ///Writes textual representation to the buffer
50 ///
51 ///Returns `str` stored in the provided `buffer`
52 ///
53 ///Can panic, if buffer is not sufficient.
54 ///Or write only partially
55 ///
56 ///Implementation is allowed to write any part of the buffer.
57 ///It is not allowed to read it, unless it was written already.
58 ///
59 ///# Safety:
60 ///
61 ///Debug builds must never invoke UB when calling this function.
62 ///
63 ///UB in release mode is fine if one wants to write efficient code.
64 fn to_str<'a>(&self, buffer: &'a mut [u8]) -> &'a str;
65
66 #[inline]
67 ///Performs textual conversion by writing to the buffer, if possible.
68 ///
69 ///If not possible MUST return `None`
70 ///
71 ///By default returns `None` if buffer size is below `TEXT_SIZE`
72 ///Otherwise calls `to_str()` while passing buffer as it is
73 fn to_str_if<'a>(&self, buffer: &'a mut [u8]) -> Option<&'a str> {
74 if buffer.len() < Self::TEXT_SIZE {
75 None
76 } else {
77 Some(self.to_str(buffer))
78 }
79 }
80}
81
82unsafe impl<'a, T: ?Sized + ToStr> ToStr for &'a T {
83 const TEXT_SIZE: usize = T::TEXT_SIZE;
84
85 #[inline(always)]
86 fn to_str<'b>(&self, buffer: &'b mut [u8]) -> &'b str {
87 (&**self).to_str(buffer)
88 }
89}
90
91unsafe impl<'a, T: ?Sized + ToStr> ToStr for &'a mut T {
92 const TEXT_SIZE: usize = T::TEXT_SIZE;
93
94 #[inline(always)]
95 fn to_str<'b>(&self, buffer: &'b mut [u8]) -> &'b str {
96 (&**self).to_str(buffer)
97 }
98}