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