1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
//! `no_std` friendly interface for conversion to str
//!
//! ```
//! type Buffer = to_str::Buffer64;
//!
//! let mut buf = String::new();
//! let _ = buf.push_str(Buffer::fmt(5usize).as_str());
//! assert_eq!(buf, "5");
//!
//! buf.push_str(Buffer::fmt(0usize).as_str());
//! assert_eq!(buf, "50");
//! buf.push_str(Buffer::fmt(&5usize).as_str());
//! assert_eq!(buf, "505");
//! buf.push_str(Buffer::fmt(&mut 0usize).as_str());
//! assert_eq!(buf, "5050");
//! ```

#![warn(missing_docs)]
#![cfg_attr(feature = "cargo-clippy", allow(clippy::style))]
#![no_std]

mod buffer;
mod numeric;

pub use buffer::Buffer;

///Alias to buffer that can be used to write `128` bit integers
pub type Buffer128 = Buffer<[u8; i128::TEXT_SIZE]>;
///Alias to buffer that can be used to write `64` bit integers
pub type Buffer64 = Buffer<[u8; i64::TEXT_SIZE]>;
///Alias to buffer that can be used to write `32` bit integers
pub type Buffer32 = Buffer<[u8; i32::TEXT_SIZE]>;
///Alias to buffer that can be used to write `isize` bit integers
pub type BufferSized = Buffer<[u8; isize::TEXT_SIZE]>;

///Describes conversion to string
///
///This trait is unsafe due to following requirements:
///
///- Implementation must never read buffer, unless it was already written by it;
///- It writes from the end of buffer (necessary only when you use `Buffer`).
pub unsafe trait ToStr {
    ///Max size in bytes to hold the string
    ///
    ///Implementation MUST guarantee that this size of buffer is enough to fit any possible textual
    ///representation
    const TEXT_SIZE: usize;

    ///Writes textual representation to the buffer
    ///
    ///Returns `str` stored in the provided `buffer`
    ///
    ///Can panic, if buffer is not sufficient.
    ///Or write only partially
    ///
    ///Implementation is allowed to write any part of the buffer.
    ///It is not allowed to read it, unless it was written already.
    ///
    ///# Safety:
    ///
    ///Debug builds must never invoke UB when calling this function.
    ///
    ///UB in release mode is fine if one wants to write efficient code.
    fn to_str<'a>(&self, buffer: &'a mut [u8]) -> &'a str;

    #[inline]
    ///Performs textual conversion by writing to the buffer, if possible.
    ///
    ///If not possible MUST return `None`
    ///
    ///By default returns `None` if buffer size is below `TEXT_SIZE`
    ///Otherwise calls `to_str()` while passing buffer as it is
    fn to_str_if<'a>(&self, buffer: &'a mut [u8]) -> Option<&'a str> {
        if buffer.len() < Self::TEXT_SIZE {
            None
        } else {
            Some(self.to_str(buffer))
        }
    }
}

unsafe impl<'a, T: ?Sized + ToStr> ToStr for &'a T {
    const TEXT_SIZE: usize = T::TEXT_SIZE;

    #[inline(always)]
    fn to_str<'b>(&self, buffer: &'b mut [u8]) -> &'b str {
        (&**self).to_str(buffer)
    }
}

unsafe impl<'a, T: ?Sized + ToStr> ToStr for &'a mut T {
    const TEXT_SIZE: usize = T::TEXT_SIZE;

    #[inline(always)]
    fn to_str<'b>(&self, buffer: &'b mut [u8]) -> &'b str {
        (&**self).to_str(buffer)
    }
}