orengine_utils/
small_string.rs1use alloc::string::String;
12#[cfg(not(feature = "no_std"))]
13use core::fmt;
14#[cfg(not(feature = "no_std"))]
15use core::fmt::Formatter;
16use core::ops::Deref;
17#[cfg(not(feature = "no_std"))]
18use serde::de::{Error, Visitor};
19#[cfg(not(feature = "no_std"))]
20use serde::{Deserialize, Deserializer, Serialize, Serializer};
21use smallvec::SmallVec;
22
23#[derive(Clone, Eq, PartialEq, Hash, PartialOrd, Ord, Debug)]
29pub struct SmallString<const INLINE_SIZE: usize>(SmallVec<u8, INLINE_SIZE>);
30
31impl<const INLINE_SIZE: usize> SmallString<INLINE_SIZE> {
32 #[must_use]
34 pub fn empty() -> Self {
35 Self(SmallVec::new())
36 }
37
38 #[cfg(not(feature = "no_std"))]
44 pub(crate) fn fill_from_reader<R: std::io::Read>(
45 mut reader: R,
46 len: usize,
47 ) -> Result<Self, std::io::Error> {
48 let mut res = Self(SmallVec::new());
49
50 res.0.resize(len, 0);
51 reader.read_exact(&mut res.0)?;
52
53 Ok(res)
54 }
55
56 pub fn extend_from_slice(&mut self, bytes: &[u8]) {
64 self.0.extend_from_slice(bytes);
65
66 debug_assert!(core::str::from_utf8(&self.0).is_ok());
68 }
69}
70
71impl<const INLINE_SIZE: usize> From<&str> for SmallString<INLINE_SIZE> {
72 fn from(value: &str) -> Self {
73 Self(value.as_bytes().into())
74 }
75}
76
77impl<const INLINE_SIZE: usize> From<String> for SmallString<INLINE_SIZE> {
78 fn from(value: String) -> Self {
79 Self(value.into_bytes().into())
80 }
81}
82
83impl<const INLINE_SIZE: usize> Deref for SmallString<INLINE_SIZE> {
84 type Target = str;
85
86 fn deref(&self) -> &Self::Target {
87 core::str::from_utf8(&self.0).unwrap()
88 }
89}
90
91#[cfg(not(feature = "no_std"))]
92impl<const INLINE_SIZE: usize> Serialize for SmallString<INLINE_SIZE> {
93 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
94 where
95 S: Serializer,
96 {
97 serializer.serialize_str(self)
98 }
99}
100
101#[cfg(not(feature = "no_std"))]
102impl<'de, const INLINE_SIZE: usize> Deserialize<'de> for SmallString<INLINE_SIZE> {
103 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
104 where
105 D: Deserializer<'de>,
106 {
107 struct SmallStringVisitor<const INLINE_SIZE: usize>;
108
109 impl<const INLINE_SIZE: usize> Visitor<'_> for SmallStringVisitor<INLINE_SIZE> {
110 type Value = SmallString<INLINE_SIZE>;
111
112 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
113 formatter.write_str("a UTF-8 string")
114 }
115
116 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
117 where
118 E: Error,
119 {
120 Ok(SmallString::from(value))
121 }
122 }
123
124 deserializer.deserialize_str(SmallStringVisitor::<INLINE_SIZE>)
125 }
126
127 fn deserialize_in_place<D>(deserializer: D, place: &mut Self) -> Result<(), D::Error>
128 where
129 D: Deserializer<'de>,
130 {
131 struct SmallStringVisitorRef<'a, const INLINE_SIZE: usize>(
132 &'a mut SmallString<INLINE_SIZE>,
133 );
134
135 impl<const INLINE_SIZE: usize> Visitor<'_> for SmallStringVisitorRef<'_, INLINE_SIZE> {
136 type Value = ();
137
138 fn expecting(&self, formatter: &mut Formatter) -> fmt::Result {
139 formatter.write_str("a UTF-8 string")
140 }
141
142 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
143 where
144 E: Error,
145 {
146 self.0 .0.clear();
147 self.0 .0.extend_from_slice(value.as_bytes());
148
149 Ok(())
150 }
151 }
152
153 deserializer.deserialize_str(SmallStringVisitorRef(place))?;
154
155 Ok(())
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::SmallString;
162 use alloc::string::String;
163
164 #[test]
165 fn empty_string_is_empty() {
166 let value = SmallString::<16>::empty();
167
168 assert!(value.is_empty());
169 }
170
171 #[test]
172 fn extend_appends_bytes() {
173 let mut value = SmallString::<8>::from("hello");
174
175 value.extend_from_slice(b" world");
176
177 assert_eq!(&*value, "hello world");
178 }
179
180 #[test]
181 fn from_string_and_str_are_equal() {
182 let a = SmallString::<8>::from("example");
183 let b = SmallString::<8>::from(String::from("example"));
184
185 assert_eq!(a, b);
186 }
187
188 #[test]
189 #[cfg(not(feature = "no_std"))]
190 fn serde() {
191 use crate::rw_serde::RWDeserializer;
192 use crate::rw_serde::RWSerializer;
193 use serde::{Deserialize, Serialize};
194 use std::io::Cursor;
195
196 let value = SmallString::<8>::from("small string");
197 let mut ser = RWSerializer::new(Vec::new());
198
199 value.serialize(&mut ser).unwrap();
200
201 let buf = ser.into_inner();
202 let mut de = RWDeserializer::new(Cursor::new(buf));
203 let restored = SmallString::<8>::deserialize(&mut de).unwrap();
204
205 assert_eq!(value, restored);
206 }
207}