1use std::borrow::Cow;
2use std::ffi::{c_char, c_int, OsStr};
3use std::mem::ManuallyDrop;
4use std::path::PathBuf;
5use std::string::{self, String as StdString};
6use std::{fmt, slice, str};
7
8use lua::{ffi::*, Poppable, Pushable};
9use luajit_bindings as lua;
10
11use crate::NonOwning;
12
13#[derive(Eq, Ord, PartialOrd, Hash)]
28#[repr(C)]
29pub struct String {
30 pub(crate) data: *mut c_char,
31 pub(crate) size: usize,
32}
33
34impl String {
35 #[inline]
36 pub fn new() -> Self {
38 Self { data: std::ptr::null_mut(), size: 0 }
39 }
40
41 #[inline]
43 pub fn from_bytes(mut vec: Vec<u8>) -> Self {
44 vec.reserve_exact(1);
45 Vec::push(&mut vec, 0);
46
47 let size = vec.len() - 1;
48 let data = vec.leak().as_mut_ptr() as *mut c_char;
49
50 Self { data, size }
51 }
52
53 #[inline]
56 pub const fn is_empty(&self) -> bool {
57 self.len() == 0
58 }
59
60 #[inline]
63 pub const fn len(&self) -> usize {
64 self.size
65 }
66
67 #[inline]
69 pub const fn as_ptr(&self) -> *const c_char {
70 self.data as *const c_char
71 }
72
73 #[inline]
75 pub fn as_bytes(&self) -> &[u8] {
76 if self.data.is_null() {
77 &[]
78 } else {
79 unsafe { slice::from_raw_parts(self.data as *const u8, self.size) }
80 }
81 }
82
83 #[inline]
86 pub fn as_str(&self) -> Result<&str, str::Utf8Error> {
87 str::from_utf8(self.as_bytes())
88 }
89
90 #[inline]
94 pub fn to_string_lossy(&self) -> Cow<'_, str> {
95 StdString::from_utf8_lossy(self.as_bytes())
96 }
97
98 #[inline]
100 pub fn into_bytes(self) -> Vec<u8> {
101 if self.data.is_null() {
102 Vec::new()
103 } else {
104 unsafe {
105 let mdrop = ManuallyDrop::new(self);
106 Vec::from_raw_parts(
107 mdrop.data.cast::<u8>(),
108 mdrop.size,
109 mdrop.size,
110 )
111 }
112 }
113 }
114
115 #[inline]
118 pub fn into_string(self) -> Result<StdString, string::FromUtf8Error> {
119 StdString::from_utf8(self.into_bytes())
120 }
121
122 #[inline]
124 #[doc(hidden)]
125 pub fn non_owning(&self) -> NonOwning<'_, String> {
126 NonOwning::new(Self { ..*self })
127 }
128}
129
130impl Default for String {
131 #[inline]
132 fn default() -> Self {
133 Self::new()
134 }
135}
136
137impl fmt::Debug for String {
138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139 fmt::Display::fmt(self, f)
140 }
141}
142
143impl fmt::Display for String {
144 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
145 f.write_str(&self.to_string_lossy())
146 }
147}
148
149impl Clone for String {
150 fn clone(&self) -> Self {
151 Self::from_bytes(self.as_bytes().to_owned())
152 }
153}
154
155impl Drop for String {
156 fn drop(&mut self) {
157 let _ = unsafe {
159 Vec::from_raw_parts(self.data, self.size + 1, self.size + 1)
160 };
161 }
162}
163
164impl From<StdString> for String {
165 #[inline]
166 fn from(string: StdString) -> Self {
167 Self::from_bytes(string.into_bytes())
168 }
169}
170
171impl From<&str> for String {
172 #[inline]
173 fn from(str: &str) -> Self {
174 Self::from_bytes(str.as_bytes().to_owned())
175 }
176}
177
178impl From<char> for String {
179 #[inline]
180 fn from(ch: char) -> Self {
181 ch.to_string().into()
182 }
183}
184
185impl From<Cow<'_, str>> for String {
186 #[inline]
187 fn from(moo: Cow<'_, str>) -> Self {
188 moo.into_owned().into()
189 }
190}
191
192impl From<Vec<u8>> for String {
193 #[inline]
194 fn from(vec: Vec<u8>) -> Self {
195 Self::from_bytes(vec)
196 }
197}
198
199impl From<PathBuf> for String {
200 #[inline]
201 fn from(path: PathBuf) -> Self {
202 path.display().to_string().into()
203 }
204}
205
206#[cfg(not(windows))]
207impl From<String> for PathBuf {
208 #[inline]
209 fn from(nstr: String) -> Self {
210 use std::os::unix::ffi::OsStrExt;
211 OsStr::from_bytes(nstr.as_bytes()).to_owned().into()
212 }
213}
214
215#[cfg(windows)]
216impl From<String> for PathBuf {
217 #[inline]
218 fn from(nstr: String) -> Self {
219 StdString::from_utf8_lossy(nstr.as_bytes()).into_owned().into()
220 }
221}
222
223impl PartialEq<Self> for String {
224 #[inline]
225 fn eq(&self, other: &Self) -> bool {
226 self.as_bytes() == other.as_bytes()
227 }
228}
229
230impl PartialEq<str> for String {
231 #[inline]
232 fn eq(&self, other: &str) -> bool {
233 self.as_bytes() == other.as_bytes()
234 }
235}
236
237impl PartialEq<&str> for String {
238 #[inline]
239 fn eq(&self, other: &&str) -> bool {
240 self.as_bytes() == other.as_bytes()
241 }
242}
243
244impl PartialEq<StdString> for String {
245 #[inline]
246 fn eq(&self, other: &StdString) -> bool {
247 self.as_bytes() == other.as_bytes()
248 }
249}
250
251impl TryFrom<String> for StdString {
252 type Error = std::string::FromUtf8Error;
253
254 fn try_from(s: String) -> Result<Self, Self::Error> {
255 StdString::from_utf8(s.into_bytes())
256 }
257}
258
259impl Pushable for String {
260 unsafe fn push(self, lstate: *mut lua_State) -> Result<c_int, lua::Error> {
261 lua::ffi::lua_pushlstring(lstate, self.as_ptr(), self.len());
262 Ok(1)
263 }
264}
265
266impl Poppable for String {
267 unsafe fn pop(lstate: *mut lua_State) -> Result<Self, lua::Error> {
268 <StdString as Poppable>::pop(lstate).map(Into::into)
269 }
270}
271
272#[cfg(feature = "serde")]
273mod serde {
274 use std::fmt;
275
276 use serde::de::{self, Deserialize, Deserializer, Visitor};
277
278 impl<'de> Deserialize<'de> for super::String {
279 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
280 where
281 D: Deserializer<'de>,
282 {
283 struct StringVisitor;
284
285 impl<'de> Visitor<'de> for StringVisitor {
286 type Value = crate::String;
287
288 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
289 f.write_str("either a string of a byte vector")
290 }
291
292 fn visit_bytes<E>(self, b: &[u8]) -> Result<Self::Value, E>
293 where
294 E: de::Error,
295 {
296 Ok(crate::String::from_bytes(b.to_owned()))
297 }
298
299 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
300 where
301 E: de::Error,
302 {
303 Ok(crate::String::from(s))
304 }
305 }
306
307 deserializer.deserialize_str(StringVisitor)
308 }
309 }
310}
311
312#[cfg(test)]
313mod tests {
314 use super::*;
315
316 #[test]
317 fn partial_eq() {
318 let lhs = String::from("foo bar baz");
319 let rhs = String::from("foo bar baz");
320 assert_eq!(lhs, rhs);
321
322 let lhs = String::from("foo bar baz");
323 let rhs = String::from("bar foo baz");
324 assert_ne!(lhs, rhs);
325
326 let lhs = String::from("€");
327 let rhs = "€";
328 assert_eq!(lhs, rhs);
329 }
330
331 #[test]
332 fn clone() {
333 let lhs = String::from("abc");
334 let rhs = lhs.clone();
335
336 assert_eq!(lhs, rhs);
337 }
338
339 #[test]
340 fn from_string() {
341 let foo = StdString::from("foo bar baz");
342
343 let lhs = String::from(foo.as_ref());
344 let rhs = String::from(foo);
345
346 assert_eq!(lhs, rhs);
347 }
348
349 #[test]
350 fn to_bytes() {
351 let s = String::from("hello");
352 let bytes = s.into_bytes();
353 assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);
354 }
355}