wasmtime_internal_core/alloc/
string.rs1use crate::{
2 alloc::{TryClone, str_ptr_from_raw_parts, try_realloc},
3 error::OutOfMemory,
4};
5use core::{borrow::Borrow, fmt, mem, ops};
6use std_alloc::{alloc::Layout, boxed::Box, string as inner};
7
8#[derive(Default, Hash, PartialEq, Eq, PartialOrd, Ord)]
11pub struct TryString {
12 inner: inner::String,
13}
14
15impl TryClone for TryString {
16 fn try_clone(&self) -> Result<Self, OutOfMemory> {
17 let mut s = Self::new();
18 s.push_str(self)?;
19 Ok(s)
20 }
21}
22
23impl fmt::Debug for TryString {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 fmt::Debug::fmt(&self.inner, f)
26 }
27}
28
29impl fmt::Display for TryString {
30 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31 fmt::Display::fmt(&self.inner, f)
32 }
33}
34
35impl ops::Deref for TryString {
36 type Target = str;
37
38 #[inline]
39 fn deref(&self) -> &Self::Target {
40 &self.inner
41 }
42}
43
44impl ops::DerefMut for TryString {
45 #[inline]
46 fn deref_mut(&mut self) -> &mut Self::Target {
47 &mut self.inner
48 }
49}
50
51impl AsRef<str> for TryString {
52 fn as_ref(&self) -> &str {
53 self
54 }
55}
56
57impl Borrow<str> for TryString {
58 fn borrow(&self) -> &str {
59 self
60 }
61}
62
63impl TryFrom<&str> for TryString {
64 type Error = OutOfMemory;
65
66 #[inline]
67 fn try_from(value: &str) -> Result<Self, Self::Error> {
68 let mut s = TryString::new();
69 s.push_str(value)?;
70 Ok(s)
71 }
72}
73
74impl From<inner::String> for TryString {
75 #[inline]
76 fn from(inner: inner::String) -> Self {
77 Self { inner }
78 }
79}
80
81impl From<TryString> for inner::String {
82 #[inline]
83 fn from(s: TryString) -> Self {
84 s.inner
85 }
86}
87
88#[cfg(feature = "serde")]
89impl serde::ser::Serialize for TryString {
90 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
91 where
92 S: serde::Serializer,
93 {
94 serializer.serialize_str(self)
95 }
96}
97
98#[cfg(feature = "serde")]
99impl<'de> serde::de::Deserialize<'de> for TryString {
100 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101 where
102 D: serde::Deserializer<'de>,
103 {
104 struct Visitor;
105
106 impl<'de> serde::de::Visitor<'de> for Visitor {
107 type Value = TryString;
108
109 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
110 f.write_str("a `wasmtime_core::alloc::String` str")
111 }
112
113 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
114 where
115 E: serde::de::Error,
116 {
117 let mut s = TryString::new();
118 s.reserve_exact(v.len()).map_err(|oom| E::custom(oom))?;
119 s.push_str(v).expect("reserved capacity");
120 Ok(s)
121 }
122 }
123
124 deserializer.deserialize_str(Visitor)
129 }
130}
131
132impl TryString {
133 #[inline]
135 pub fn new() -> Self {
136 Self {
137 inner: inner::String::new(),
138 }
139 }
140
141 #[inline]
144 pub fn with_capacity(capacity: usize) -> Result<Self, OutOfMemory> {
145 let mut s = Self::new();
146 s.reserve(capacity)?;
147 Ok(s)
148 }
149
150 #[inline]
152 pub fn capacity(&self) -> usize {
153 self.inner.capacity()
154 }
155
156 #[inline]
158 pub const fn as_str(&self) -> &str {
159 self.inner.as_str()
160 }
161
162 #[inline]
165 pub fn reserve(&mut self, additional: usize) -> Result<(), OutOfMemory> {
166 self.inner
167 .try_reserve(additional)
168 .map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
169 }
170
171 #[inline]
174 pub fn reserve_exact(&mut self, additional: usize) -> Result<(), OutOfMemory> {
175 self.inner
176 .try_reserve_exact(additional)
177 .map_err(|_| OutOfMemory::new(self.len().saturating_add(additional)))
178 }
179
180 #[inline]
183 pub fn push(&mut self, c: char) -> Result<(), OutOfMemory> {
184 self.reserve(c.len_utf8())?;
185 self.inner.push(c);
186 Ok(())
187 }
188
189 #[inline]
192 pub fn push_str(&mut self, s: &str) -> Result<(), OutOfMemory> {
193 self.reserve(s.len())?;
194 self.inner.push_str(s);
195 Ok(())
196 }
197
198 pub fn into_raw_parts(mut self) -> (*mut u8, usize, usize) {
200 #[cfg(not(miri))]
202 {
203 let ptr = self.as_mut_ptr();
204 let len = self.len();
205 let cap = self.capacity();
206 mem::forget(self);
207 (ptr, len, cap)
208 }
209 #[cfg(miri)]
212 {
213 let _ = &mut self;
214 self.inner.into_raw_parts()
215 }
216 }
217
218 pub unsafe fn from_raw_parts(buf: *mut u8, length: usize, capacity: usize) -> Self {
220 Self {
221 inner: unsafe { inner::String::from_raw_parts(buf, length, capacity) },
223 }
224 }
225
226 pub fn shrink_to_fit(&mut self) -> Result<(), OutOfMemory> {
229 if self.len() == self.capacity() {
232 return Ok(());
233 }
234
235 if self.is_empty() {
246 self.inner.shrink_to_fit();
247 return Ok(());
248 }
249
250 let (ptr, len, cap) = mem::take(self).into_raw_parts();
251 debug_assert!(!ptr.is_null());
252 debug_assert!(len > 0);
253 debug_assert!(cap > len);
254 let old_layout = Layout::array::<u8>(cap).unwrap();
255 debug_assert_eq!(old_layout.size(), cap);
256 let new_layout = Layout::array::<u8>(len).unwrap();
257 debug_assert_eq!(old_layout.align(), new_layout.align());
258 debug_assert_eq!(new_layout.size(), len);
259
260 let result = unsafe { try_realloc(ptr, old_layout, len) };
265
266 match result {
267 Ok(ptr) => {
268 *self = unsafe { Self::from_raw_parts(ptr.as_ptr(), len, len) };
271 Ok(())
272 }
273 Err(oom) => {
274 *self = unsafe { Self::from_raw_parts(ptr, len, cap) };
278 Err(oom)
279 }
280 }
281 }
282
283 pub fn into_boxed_str(mut self) -> Result<Box<str>, OutOfMemory> {
286 self.shrink_to_fit()?;
287
288 let (ptr, len, cap) = self.into_raw_parts();
289 debug_assert_eq!(len, cap);
290 let ptr = str_ptr_from_raw_parts(ptr, len);
291
292 let boxed = unsafe { Box::from_raw(ptr) };
295
296 Ok(boxed)
297 }
298}