1- use std:: borrow:: { Borrow , Cow } ;
1+ use std:: borrow:: Borrow ;
22use std:: hash:: { Hash , Hasher } ;
3+ use std:: ops:: Deref ;
34use std:: os:: raw:: c_void;
45use std:: string:: String as StdString ;
5- use std:: { fmt, slice, str} ;
6+ use std:: { cmp , fmt, slice, str} ;
67
78#[ cfg( feature = "serialize" ) ]
89use {
1112} ;
1213
1314use crate :: error:: { Error , Result } ;
15+ use crate :: state:: LuaGuard ;
1416use crate :: types:: ValueRef ;
1517
1618/// Handle to an internal Lua string.
@@ -20,7 +22,7 @@ use crate::types::ValueRef;
2022pub struct String ( pub ( crate ) ValueRef ) ;
2123
2224impl String {
23- /// Get a `&str` slice if the Lua string is valid UTF-8.
25+ /// Get a [`BorrowedStr`] if the Lua string is valid UTF-8.
2426 ///
2527 /// # Examples
2628 ///
@@ -39,15 +41,17 @@ impl String {
3941 /// # }
4042 /// ```
4143 #[ inline]
42- pub fn to_str ( & self ) -> Result < & str > {
43- str:: from_utf8 ( self . as_bytes ( ) ) . map_err ( |e| Error :: FromLuaConversionError {
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 {
4447 from : "string" ,
4548 to : "&str" ,
4649 message : Some ( e. to_string ( ) ) ,
47- } )
50+ } ) ?;
51+ Ok ( BorrowedStr ( s, guard) )
4852 }
4953
50- /// Converts this string to a [`Cow<str> `].
54+ /// Converts this string to a [`StdString `].
5155 ///
5256 /// Any non-Unicode sequences are replaced with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
5357 ///
@@ -66,8 +70,8 @@ impl String {
6670 /// # }
6771 /// ```
6872 #[ inline]
69- pub fn to_string_lossy ( & self ) -> Cow < ' _ , str > {
70- StdString :: from_utf8_lossy ( self . as_bytes ( ) )
73+ pub fn to_string_lossy ( & self ) -> StdString {
74+ StdString :: from_utf8_lossy ( & self . as_bytes ( ) ) . into_owned ( )
7175 }
7276
7377 /// Get the bytes that make up this string.
@@ -88,13 +92,18 @@ impl String {
8892 /// # }
8993 /// ```
9094 #[ inline]
91- pub fn as_bytes ( & self ) -> & [ u8 ] {
92- let nulled = self . as_bytes_with_nul ( ) ;
93- & nulled [ ..nulled . len ( ) - 1 ]
95+ pub fn as_bytes ( & self ) -> BorrowedBytes {
96+ let ( bytes , guard ) = unsafe { self . to_slice ( ) } ;
97+ BorrowedBytes ( & bytes [ ..bytes . len ( ) - 1 ] , guard )
9498 }
9599
96100 /// Get the bytes that make up this string, including the trailing nul byte.
97- pub fn as_bytes_with_nul ( & self ) -> & [ u8 ] {
101+ 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 ] , LuaGuard ) {
98107 let lua = self . 0 . lua . lock ( ) ;
99108 let ref_thread = lua. ref_thread ( ) ;
100109 unsafe {
@@ -108,7 +117,7 @@ impl String {
108117 // string type
109118 let data = ffi:: lua_tolstring ( ref_thread, self . 0 . index , & mut size) ;
110119
111- slice:: from_raw_parts ( data as * const u8 , size + 1 )
120+ ( slice:: from_raw_parts ( data as * const u8 , size + 1 ) , lua )
112121 }
113122 }
114123
@@ -127,7 +136,7 @@ impl fmt::Debug for String {
127136 fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
128137 let bytes = self . as_bytes ( ) ;
129138 // Check if the string is valid utf8
130- if let Ok ( s) = str:: from_utf8 ( bytes) {
139+ if let Ok ( s) = str:: from_utf8 ( & bytes) {
131140 return s. fmt ( f) ;
132141 }
133142
@@ -152,22 +161,9 @@ impl fmt::Debug for String {
152161 }
153162}
154163
155- impl AsRef < [ u8 ] > for String {
156- fn as_ref ( & self ) -> & [ u8 ] {
157- self . as_bytes ( )
158- }
159- }
160-
161- impl Borrow < [ u8 ] > for String {
162- fn borrow ( & self ) -> & [ u8 ] {
163- self . as_bytes ( )
164- }
165- }
166-
167164// Lua strings are basically &[u8] slices, so implement PartialEq for anything resembling that.
168165//
169- // This makes our `String` comparable with `Vec<u8>`, `[u8]`, `&str`, `String` and `mlua::String`
170- // itself.
166+ // This makes our `String` comparable with `Vec<u8>`, `[u8]`, `&str` and `String`.
171167//
172168// The only downside is that this disallows a comparison with `Cow<str>`, as that only implements
173169// `AsRef<str>`, which collides with this impl. Requiring `AsRef<str>` would fix that, but limit us
@@ -181,6 +177,18 @@ where
181177 }
182178}
183179
180+ impl PartialEq < String > for String {
181+ fn eq ( & self , other : & String ) -> bool {
182+ self . as_bytes ( ) == other. as_bytes ( )
183+ }
184+ }
185+
186+ impl PartialEq < & String > for String {
187+ fn eq ( & self , other : & & String ) -> bool {
188+ self . as_bytes ( ) == other. as_bytes ( )
189+ }
190+ }
191+
184192impl Eq for String { }
185193
186194impl Hash for String {
@@ -196,12 +204,127 @@ impl Serialize for String {
196204 S : Serializer ,
197205 {
198206 match self . to_str ( ) {
199- Ok ( s) => serializer. serialize_str ( s) ,
200- Err ( _) => serializer. serialize_bytes ( self . as_bytes ( ) ) ,
207+ Ok ( s) => serializer. serialize_str ( & s) ,
208+ Err ( _) => serializer. serialize_bytes ( & self . as_bytes ( ) ) ,
201209 }
202210 }
203211}
204212
213+ /// A borrowed string (`&str`) that holds a strong reference to the Lua state.
214+ pub struct BorrowedStr < ' a > ( & ' a str , #[ allow( unused) ] LuaGuard ) ;
215+
216+ impl Deref for BorrowedStr < ' _ > {
217+ type Target = str ;
218+
219+ #[ inline( always) ]
220+ fn deref ( & self ) -> & str {
221+ self . 0
222+ }
223+ }
224+
225+ impl Borrow < str > for BorrowedStr < ' _ > {
226+ #[ inline( always) ]
227+ fn borrow ( & self ) -> & str {
228+ self . 0
229+ }
230+ }
231+
232+ impl AsRef < str > for BorrowedStr < ' _ > {
233+ #[ inline( always) ]
234+ fn as_ref ( & self ) -> & str {
235+ self . 0
236+ }
237+ }
238+
239+ impl fmt:: Display for BorrowedStr < ' _ > {
240+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
241+ self . 0 . fmt ( f)
242+ }
243+ }
244+
245+ impl fmt:: Debug for BorrowedStr < ' _ > {
246+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
247+ self . 0 . fmt ( f)
248+ }
249+ }
250+
251+ impl < T > PartialEq < T > for BorrowedStr < ' _ >
252+ where
253+ T : AsRef < str > ,
254+ {
255+ fn eq ( & self , other : & T ) -> bool {
256+ self . 0 == other. as_ref ( )
257+ }
258+ }
259+
260+ impl < T > PartialOrd < T > for BorrowedStr < ' _ >
261+ where
262+ T : AsRef < str > ,
263+ {
264+ fn partial_cmp ( & self , other : & T ) -> Option < cmp:: Ordering > {
265+ self . 0 . partial_cmp ( other. as_ref ( ) )
266+ }
267+ }
268+
269+ /// A borrowed byte slice (`&[u8]`) that holds a strong reference to the Lua state.
270+ pub struct BorrowedBytes < ' a > ( & ' a [ u8 ] , #[ allow( unused) ] LuaGuard ) ;
271+
272+ impl Deref for BorrowedBytes < ' _ > {
273+ type Target = [ u8 ] ;
274+
275+ #[ inline( always) ]
276+ fn deref ( & self ) -> & [ u8 ] {
277+ self . 0
278+ }
279+ }
280+
281+ impl Borrow < [ u8 ] > for BorrowedBytes < ' _ > {
282+ #[ inline( always) ]
283+ fn borrow ( & self ) -> & [ u8 ] {
284+ self . 0
285+ }
286+ }
287+
288+ impl AsRef < [ u8 ] > for BorrowedBytes < ' _ > {
289+ #[ inline( always) ]
290+ fn as_ref ( & self ) -> & [ u8 ] {
291+ self . 0
292+ }
293+ }
294+
295+ impl fmt:: Debug for BorrowedBytes < ' _ > {
296+ fn fmt ( & self , f : & mut fmt:: Formatter ) -> fmt:: Result {
297+ self . 0 . fmt ( f)
298+ }
299+ }
300+
301+ impl < T > PartialEq < T > for BorrowedBytes < ' _ >
302+ where
303+ T : AsRef < [ u8 ] > ,
304+ {
305+ fn eq ( & self , other : & T ) -> bool {
306+ self . 0 == other. as_ref ( )
307+ }
308+ }
309+
310+ impl < T > PartialOrd < T > for BorrowedBytes < ' _ >
311+ where
312+ T : AsRef < [ u8 ] > ,
313+ {
314+ fn partial_cmp ( & self , other : & T ) -> Option < cmp:: Ordering > {
315+ self . 0 . partial_cmp ( other. as_ref ( ) )
316+ }
317+ }
318+
319+ impl < ' a > IntoIterator for BorrowedBytes < ' a > {
320+ type Item = & ' a u8 ;
321+ type IntoIter = slice:: Iter < ' a , u8 > ;
322+
323+ fn into_iter ( self ) -> Self :: IntoIter {
324+ self . 0 . into_iter ( )
325+ }
326+ }
327+
205328#[ cfg( test) ]
206329mod assertions {
207330 use super :: * ;
0 commit comments