Skip to main content

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