1 use core
::borrow
::Borrow
;
2 use core
::cmp
::Ordering
;
4 use core
::hash
::{Hash
, Hasher
};
8 /// A string of runtime-determined length that stores its contents inline.
10 /// This type exists for the sake of performance and avoiding allocation (including no-std
11 /// operation). It dereferences to [`prim@str`] and also implements most of the useful traits that
12 /// `str` and/or `String` implement, so you can mostly just treat it as any other string. If you
13 /// want to explicitly convert it to `&str`, there’s `.as_str()`, and to `String`, `.to_string()`
14 /// or any of the other similar techniques.
16 /// From an implementation perspective, this is designed for efficient base-conversion: the biggest
17 /// consequence of this is that the string is *right*-aligned within its capacity, rather than the
18 /// usual left. It thus stores a start offset instead of a length.
20 pub struct InlineString
<const CAPACITY
: usize> {
21 /// SAFETY requirement: buf[start..CAPACITY] must be valid UTF-8.
22 pub(crate) buf
: [u8; CAPACITY
],
23 /// SAFETY requirement: start <= CAPACITY.
24 pub(crate) start
: usize,
27 impl<const CAPACITY
: usize> InlineString
<CAPACITY
> {
28 /// Access this as an `&str`.
29 // (Sorry, no const as const_slice_index isn’t yet stable.)
30 pub fn as_str(&self) -> &str {
31 // SAFETY: both unchecked calls here correspond to declared invariants.
32 unsafe { str::from_utf8_unchecked(self.buf
.get_unchecked(self.start
..)) }
36 impl<const CAPACITY
: usize> Deref
for InlineString
<CAPACITY
> {
38 fn deref(&self) -> &str {
43 impl<const CAPACITY
: usize> fmt
::Display
for InlineString
<CAPACITY
> {
44 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
49 impl<const CAPACITY
: usize> fmt
::Debug
for InlineString
<CAPACITY
> {
50 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
55 impl<const C1
: usize, const C2
: usize> PartialEq
<InlineString
<C2
>> for InlineString
<C1
> {
56 fn eq(&self, rhs
: &InlineString
<C2
>) -> bool
{
57 self.as_str() == rhs
.as_str()
61 impl<const CAPACITY
: usize> PartialEq
<str> for InlineString
<CAPACITY
> {
62 fn eq(&self, rhs
: &str) -> bool
{
67 impl<const CAPACITY
: usize> PartialEq
<&str> for InlineString
<CAPACITY
> {
68 fn eq(&self, rhs
: &&str) -> bool
{
73 impl<const CAPACITY
: usize> Eq
for InlineString
<CAPACITY
> {}
75 impl<const CAPACITY
: usize> AsRef
<str> for InlineString
<CAPACITY
> {
76 fn as_ref(&self) -> &str {
81 impl<const CAPACITY
: usize> Borrow
<str> for InlineString
<CAPACITY
> {
82 fn borrow(&self) -> &str {
87 impl<const CAPACITY
: usize> Hash
for InlineString
<CAPACITY
> {
88 fn hash
<H
: Hasher
>(&self, state
: &mut H
) {
89 self.as_str().hash(state
)
93 impl<const CAPACITY
: usize> PartialOrd
for InlineString
<CAPACITY
> {
94 fn partial_cmp(&self, rhs
: &InlineString
<CAPACITY
>) -> Option
<Ordering
> {
95 self.as_str().partial_cmp(rhs
.as_str())
99 impl<const CAPACITY
: usize> Ord
for InlineString
<CAPACITY
> {
100 fn cmp(&self, rhs
: &InlineString
<CAPACITY
>) -> Ordering
{
101 self.as_str().cmp(rhs
.as_str())
106 fn test_implementations() {
107 // SAFETY: all trivially meet the requirements about buf and start.
108 let s1
= InlineString
{ buf
: *b
"He\xE2\x84\x93lo!\n", start
: 0 };
109 let s2
= InlineString
{ buf
: *b
"unusedHe\xE2\x84\x93lo!\n", start
: 6 };
110 let s3
= InlineString
{ buf
: *b
"He\xE2\x84\x93lo?\n", start
: 0 };
112 assert_eq!(s1
, "Heℓlo!\n");
116 assert_eq!(s2
, "Heℓlo!\n");
120 assert_eq!(s3
, "Heℓlo?\n");
121 assert_ne!(s3
, "Heℓlo!\n");
125 // Eh, you know what? I’m bored, can’t be bothered writing tests for AsRef, Borrow, Hash,
126 // PartialOrd, Ord. But they’re all similarly trivial, and PartialEq was really the most
127 // interesting, with its multiple implementations.
131 #[cfg(feature = "std")] // format! is std. As this is the only test yet that needs std⸺
132 fn test_fmt_implementations() {
133 // SAFETY: all trivially meet the requirements about buf and start.
134 let s1
= InlineString
{ buf
: *b
"He\xE2\x84\x93lo!\n", start
: 0 };
135 let s2
= InlineString
{ buf
: *b
"unusedHe\xE2\x84\x93lo!\n", start
: 6 };
136 assert_eq!(format!("{s1}"), "Heℓlo!\n");
137 assert_eq!(format!("{s1:?}"), "\"Heℓlo!\\n\"");
138 assert_eq!(format!("{s2}"), "Heℓlo!\n");
139 assert_eq!(format!("{s2:?}"), "\"Heℓlo!\\n\"");