mlua_codemp_patch/
string.rs1use std::borrow::Borrow;
2use std::hash::{Hash, Hasher};
3use std::ops::Deref;
4use std::os::raw::c_void;
5use std::string::String as StdString;
6use std::{cmp, fmt, slice, str};
7
8#[cfg(feature = "serialize")]
9use {
10 serde::ser::{Serialize, Serializer},
11 std::result::Result as StdResult,
12};
13
14use crate::error::{Error, Result};
15use crate::state::Lua;
16use crate::types::ValueRef;
17
18#[derive(Clone)]
22pub struct String(pub(crate) ValueRef);
23
24impl String {
25 #[inline]
44 pub fn to_str(&self) -> Result<BorrowedStr> {
45 let BorrowedBytes(bytes, guard) = self.as_bytes();
46 let s = str::from_utf8(bytes).map_err(|e| Error::FromLuaConversionError {
47 from: "string",
48 to: "&str",
49 message: Some(e.to_string()),
50 })?;
51 Ok(BorrowedStr(s, guard))
52 }
53
54 #[inline]
73 pub fn to_string_lossy(&self) -> StdString {
74 StdString::from_utf8_lossy(&self.as_bytes()).into_owned()
75 }
76
77 #[inline]
95 pub fn as_bytes(&self) -> BorrowedBytes {
96 let (bytes, guard) = unsafe { self.to_slice() };
97 BorrowedBytes(&bytes[..bytes.len() - 1], guard)
98 }
99
100 pub fn as_bytes_with_nul(&self) -> BorrowedBytes {
102 let (bytes, guard) = unsafe { self.to_slice() };
103 BorrowedBytes(bytes, guard)
104 }
105
106 unsafe fn to_slice(&self) -> (&[u8], Lua) {
107 let lua = self.0.lua.upgrade();
108 let rawlua = lua.lock();
109 let ref_thread = rawlua.ref_thread();
110 unsafe {
111 mlua_debug_assert!(
112 ffi::lua_type(ref_thread, self.0.index) == ffi::LUA_TSTRING,
113 "string ref is not string type"
114 );
115
116 let mut size = 0;
117 let data = ffi::lua_tolstring(ref_thread, self.0.index, &mut size);
120
121 drop(rawlua);
122 (slice::from_raw_parts(data as *const u8, size + 1), lua)
123 }
124 }
125
126 #[inline]
132 pub fn to_pointer(&self) -> *const c_void {
133 self.0.to_pointer()
134 }
135}
136
137impl fmt::Debug for String {
138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139 let bytes = self.as_bytes();
140 if let Ok(s) = str::from_utf8(&bytes) {
142 return s.fmt(f);
143 }
144
145 write!(f, "b\"")?;
147 for &b in bytes {
148 match b {
150 b'\n' => write!(f, "\\n")?,
151 b'\r' => write!(f, "\\r")?,
152 b'\t' => write!(f, "\\t")?,
153 b'\\' | b'"' => write!(f, "\\{}", b as char)?,
154 b'\0' => write!(f, "\\0")?,
155 0x20..=0x7e => write!(f, "{}", b as char)?,
157 _ => write!(f, "\\x{b:02x}")?,
158 }
159 }
160 write!(f, "\"")?;
161
162 Ok(())
163 }
164}
165
166impl<T> PartialEq<T> for String
174where
175 T: AsRef<[u8]> + ?Sized,
176{
177 fn eq(&self, other: &T) -> bool {
178 self.as_bytes() == other.as_ref()
179 }
180}
181
182impl PartialEq<String> for String {
183 fn eq(&self, other: &String) -> bool {
184 self.as_bytes() == other.as_bytes()
185 }
186}
187
188impl PartialEq<&String> for String {
189 fn eq(&self, other: &&String) -> bool {
190 self.as_bytes() == other.as_bytes()
191 }
192}
193
194impl Eq for String {}
195
196impl Hash for String {
197 fn hash<H: Hasher>(&self, state: &mut H) {
198 self.as_bytes().hash(state);
199 }
200}
201
202#[cfg(feature = "serialize")]
203impl Serialize for String {
204 fn serialize<S>(&self, serializer: S) -> StdResult<S::Ok, S::Error>
205 where
206 S: Serializer,
207 {
208 match self.to_str() {
209 Ok(s) => serializer.serialize_str(&s),
210 Err(_) => serializer.serialize_bytes(&self.as_bytes()),
211 }
212 }
213}
214
215pub struct BorrowedStr<'a>(&'a str, #[allow(unused)] Lua);
217
218impl Deref for BorrowedStr<'_> {
219 type Target = str;
220
221 #[inline(always)]
222 fn deref(&self) -> &str {
223 self.0
224 }
225}
226
227impl Borrow<str> for BorrowedStr<'_> {
228 #[inline(always)]
229 fn borrow(&self) -> &str {
230 self.0
231 }
232}
233
234impl AsRef<str> for BorrowedStr<'_> {
235 #[inline(always)]
236 fn as_ref(&self) -> &str {
237 self.0
238 }
239}
240
241impl fmt::Display for BorrowedStr<'_> {
242 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
243 self.0.fmt(f)
244 }
245}
246
247impl fmt::Debug for BorrowedStr<'_> {
248 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249 self.0.fmt(f)
250 }
251}
252
253impl<T> PartialEq<T> for BorrowedStr<'_>
254where
255 T: AsRef<str>,
256{
257 fn eq(&self, other: &T) -> bool {
258 self.0 == other.as_ref()
259 }
260}
261
262impl<T> PartialOrd<T> for BorrowedStr<'_>
263where
264 T: AsRef<str>,
265{
266 fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
267 self.0.partial_cmp(other.as_ref())
268 }
269}
270
271pub struct BorrowedBytes<'a>(&'a [u8], #[allow(unused)] Lua);
273
274impl Deref for BorrowedBytes<'_> {
275 type Target = [u8];
276
277 #[inline(always)]
278 fn deref(&self) -> &[u8] {
279 self.0
280 }
281}
282
283impl Borrow<[u8]> for BorrowedBytes<'_> {
284 #[inline(always)]
285 fn borrow(&self) -> &[u8] {
286 self.0
287 }
288}
289
290impl AsRef<[u8]> for BorrowedBytes<'_> {
291 #[inline(always)]
292 fn as_ref(&self) -> &[u8] {
293 self.0
294 }
295}
296
297impl fmt::Debug for BorrowedBytes<'_> {
298 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
299 self.0.fmt(f)
300 }
301}
302
303impl<T> PartialEq<T> for BorrowedBytes<'_>
304where
305 T: AsRef<[u8]>,
306{
307 fn eq(&self, other: &T) -> bool {
308 self.0 == other.as_ref()
309 }
310}
311
312impl<T> PartialOrd<T> for BorrowedBytes<'_>
313where
314 T: AsRef<[u8]>,
315{
316 fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
317 self.0.partial_cmp(other.as_ref())
318 }
319}
320
321impl<'a> IntoIterator for BorrowedBytes<'a> {
322 type Item = &'a u8;
323 type IntoIter = slice::Iter<'a, u8>;
324
325 fn into_iter(self) -> Self::IntoIter {
326 self.0.iter()
327 }
328}
329
330#[cfg(test)]
331mod assertions {
332 use super::*;
333
334 #[cfg(not(feature = "send"))]
335 static_assertions::assert_not_impl_any!(String: Send);
336 #[cfg(feature = "send")]
337 static_assertions::assert_impl_all!(String: Send, Sync);
338 #[cfg(feature = "send")]
339 static_assertions::assert_impl_all!(BorrowedBytes: Send, Sync);
340 #[cfg(feature = "send")]
341 static_assertions::assert_impl_all!(BorrowedStr: Send, Sync);
342}