Skip to content

Commit bf0c969

Browse files
committed
Remove lifetime from BorrowedStr and BorrowedBytes
The underlying `ValueRef` is cheap to clone as only increases reference count, instead of allocating a new Lua stack slot.
1 parent 8817720 commit bf0c969

3 files changed

Lines changed: 67 additions & 73 deletions

File tree

src/conversion.rs

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::ffi::{CStr, CString, OsStr, OsString};
44
use std::hash::{BuildHasher, Hash};
55
use std::os::raw::c_int;
66
use std::path::{Path, PathBuf};
7-
use std::{mem, slice, str};
7+
use std::{slice, str};
88

99
use bstr::{BStr, BString, ByteVec};
1010
use num_traits::cast;
@@ -86,91 +86,79 @@ impl FromLua for LuaString {
8686
}
8787
}
8888

89-
impl IntoLua for BorrowedStr<'_> {
89+
impl IntoLua for BorrowedStr {
9090
#[inline]
9191
fn into_lua(self, _: &Lua) -> Result<Value> {
92-
Ok(Value::String(self.borrow.into_owned()))
92+
Ok(Value::String(LuaString(self.vref)))
9393
}
9494

9595
#[inline]
9696
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
97-
lua.push_ref(&self.borrow.0);
97+
lua.push_ref(&self.vref);
9898
Ok(())
9999
}
100100
}
101101

102-
impl IntoLua for &BorrowedStr<'_> {
102+
impl IntoLua for &BorrowedStr {
103103
#[inline]
104104
fn into_lua(self, _: &Lua) -> Result<Value> {
105-
Ok(Value::String(self.borrow.clone().into_owned()))
105+
Ok(Value::String(LuaString(self.vref.clone())))
106106
}
107107

108108
#[inline]
109109
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
110-
lua.push_ref(&self.borrow.0);
110+
lua.push_ref(&self.vref);
111111
Ok(())
112112
}
113113
}
114114

115-
impl FromLua for BorrowedStr<'_> {
115+
impl FromLua for BorrowedStr {
116116
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
117117
let s = LuaString::from_lua(value, lua)?;
118-
let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?;
119-
let buf = unsafe { mem::transmute::<&str, &'static str>(buf) };
120-
let borrow = Cow::Owned(s);
121-
Ok(Self { buf, borrow, _lua })
118+
BorrowedStr::try_from(&s)
122119
}
123120

124121
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
125122
let s = LuaString::from_stack(idx, lua)?;
126-
let BorrowedStr { buf, _lua, .. } = BorrowedStr::try_from(&s)?;
127-
let buf = unsafe { mem::transmute::<&str, &'static str>(buf) };
128-
let borrow = Cow::Owned(s);
129-
Ok(Self { buf, borrow, _lua })
123+
BorrowedStr::try_from(&s)
130124
}
131125
}
132126

133-
impl IntoLua for BorrowedBytes<'_> {
127+
impl IntoLua for BorrowedBytes {
134128
#[inline]
135129
fn into_lua(self, _: &Lua) -> Result<Value> {
136-
Ok(Value::String(self.borrow.into_owned()))
130+
Ok(Value::String(LuaString(self.vref)))
137131
}
138132

139133
#[inline]
140134
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
141-
lua.push_ref(&self.borrow.0);
135+
lua.push_ref(&self.vref);
142136
Ok(())
143137
}
144138
}
145139

146-
impl IntoLua for &BorrowedBytes<'_> {
140+
impl IntoLua for &BorrowedBytes {
147141
#[inline]
148142
fn into_lua(self, _: &Lua) -> Result<Value> {
149-
Ok(Value::String(self.borrow.clone().into_owned()))
143+
Ok(Value::String(LuaString(self.vref.clone())))
150144
}
151145

152146
#[inline]
153147
unsafe fn push_into_stack(self, lua: &RawLua) -> Result<()> {
154-
lua.push_ref(&self.borrow.0);
148+
lua.push_ref(&self.vref);
155149
Ok(())
156150
}
157151
}
158152

159-
impl FromLua for BorrowedBytes<'_> {
153+
impl FromLua for BorrowedBytes {
160154
fn from_lua(value: Value, lua: &Lua) -> Result<Self> {
161155
let s = LuaString::from_lua(value, lua)?;
162-
let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s);
163-
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
164-
let borrow = Cow::Owned(s);
165-
Ok(Self { buf, borrow, _lua })
156+
Ok(BorrowedBytes::from(&s))
166157
}
167158

168159
unsafe fn from_stack(idx: c_int, lua: &RawLua) -> Result<Self> {
169160
let s = LuaString::from_stack(idx, lua)?;
170-
let BorrowedBytes { buf, _lua, .. } = BorrowedBytes::from(&s);
171-
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
172-
let borrow = Cow::Owned(s);
173-
Ok(Self { buf, borrow, _lua })
161+
Ok(BorrowedBytes::from(&s))
174162
}
175163
}
176164

src/string.rs

Lines changed: 47 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@
1010
//! - [`BorrowedBytes`] - A borrowed `&[u8]` view of a Lua string that holds a strong reference to
1111
//! the Lua state.
1212
13-
use std::borrow::{Borrow, Cow};
13+
use std::borrow::Borrow;
1414
use std::hash::{Hash, Hasher};
1515
use std::ops::Deref;
1616
use std::os::raw::{c_int, c_void};
17-
use std::{cmp, fmt, slice, str};
17+
use std::{cmp, fmt, mem, slice, str};
1818

1919
use crate::error::{Error, Result};
2020
use crate::state::Lua;
@@ -37,6 +37,9 @@ pub struct LuaString(pub(crate) ValueRef);
3737
impl LuaString {
3838
/// Get a [`BorrowedStr`] if the Lua string is valid UTF-8.
3939
///
40+
/// The returned `BorrowedStr` holds a strong reference to the Lua state to guarantee the
41+
/// validity of the underlying data.
42+
///
4043
/// # Examples
4144
///
4245
/// ```
@@ -54,7 +57,7 @@ impl LuaString {
5457
/// # }
5558
/// ```
5659
#[inline]
57-
pub fn to_str(&self) -> Result<BorrowedStr<'_>> {
60+
pub fn to_str(&self) -> Result<BorrowedStr> {
5861
BorrowedStr::try_from(self)
5962
}
6063

@@ -97,8 +100,9 @@ impl LuaString {
97100

98101
/// Get the bytes that make up this string.
99102
///
100-
/// The returned slice will not contain the terminating null byte, but will contain any null
101-
/// bytes embedded into the Lua string.
103+
/// The returned `BorrowedStr` holds a strong reference to the Lua state to guarantee the
104+
/// validity of the underlying data. The data will not contain the terminating null byte, but
105+
/// will contain any null bytes embedded into the Lua string.
102106
///
103107
/// # Examples
104108
///
@@ -113,16 +117,16 @@ impl LuaString {
113117
/// # }
114118
/// ```
115119
#[inline]
116-
pub fn as_bytes(&self) -> BorrowedBytes<'_> {
120+
pub fn as_bytes(&self) -> BorrowedBytes {
117121
BorrowedBytes::from(self)
118122
}
119123

120124
/// Get the bytes that make up this string, including the trailing null byte.
121-
pub fn as_bytes_with_nul(&self) -> BorrowedBytes<'_> {
122-
let BorrowedBytes { buf, borrow, _lua } = BorrowedBytes::from(self);
125+
pub fn as_bytes_with_nul(&self) -> BorrowedBytes {
126+
let BorrowedBytes { buf, vref, _lua } = BorrowedBytes::from(self);
123127
// Include the trailing null byte (it's always present but excluded by default)
124128
let buf = unsafe { slice::from_raw_parts((*buf).as_ptr(), (*buf).len() + 1) };
125-
BorrowedBytes { buf, borrow, _lua }
129+
BorrowedBytes { buf, vref, _lua }
126130
}
127131

128132
// Does not return the terminating null byte
@@ -245,14 +249,14 @@ impl fmt::Display for Display<'_> {
245249
}
246250

247251
/// A borrowed string (`&str`) that holds a strong reference to the Lua state.
248-
pub struct BorrowedStr<'a> {
252+
pub struct BorrowedStr {
249253
// `buf` points to a readonly memory managed by Lua
250-
pub(crate) buf: &'a str,
251-
pub(crate) borrow: Cow<'a, LuaString>,
254+
pub(crate) buf: &'static str,
255+
pub(crate) vref: ValueRef,
252256
pub(crate) _lua: Lua,
253257
}
254258

255-
impl Deref for BorrowedStr<'_> {
259+
impl Deref for BorrowedStr {
256260
type Target = str;
257261

258262
#[inline(always)]
@@ -261,33 +265,33 @@ impl Deref for BorrowedStr<'_> {
261265
}
262266
}
263267

264-
impl Borrow<str> for BorrowedStr<'_> {
268+
impl Borrow<str> for BorrowedStr {
265269
#[inline(always)]
266270
fn borrow(&self) -> &str {
267271
self.buf
268272
}
269273
}
270274

271-
impl AsRef<str> for BorrowedStr<'_> {
275+
impl AsRef<str> for BorrowedStr {
272276
#[inline(always)]
273277
fn as_ref(&self) -> &str {
274278
self.buf
275279
}
276280
}
277281

278-
impl fmt::Display for BorrowedStr<'_> {
282+
impl fmt::Display for BorrowedStr {
279283
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
280284
self.buf.fmt(f)
281285
}
282286
}
283287

284-
impl fmt::Debug for BorrowedStr<'_> {
288+
impl fmt::Debug for BorrowedStr {
285289
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286290
self.buf.fmt(f)
287291
}
288292
}
289293

290-
impl<T> PartialEq<T> for BorrowedStr<'_>
294+
impl<T> PartialEq<T> for BorrowedStr
291295
where
292296
T: AsRef<str>,
293297
{
@@ -296,9 +300,9 @@ where
296300
}
297301
}
298302

299-
impl Eq for BorrowedStr<'_> {}
303+
impl Eq for BorrowedStr {}
300304

301-
impl<T> PartialOrd<T> for BorrowedStr<'_>
305+
impl<T> PartialOrd<T> for BorrowedStr
302306
where
303307
T: AsRef<str>,
304308
{
@@ -307,33 +311,33 @@ where
307311
}
308312
}
309313

310-
impl Ord for BorrowedStr<'_> {
314+
impl Ord for BorrowedStr {
311315
fn cmp(&self, other: &Self) -> cmp::Ordering {
312316
self.buf.cmp(other.buf)
313317
}
314318
}
315319

316-
impl<'a> TryFrom<&'a LuaString> for BorrowedStr<'a> {
320+
impl TryFrom<&LuaString> for BorrowedStr {
317321
type Error = Error;
318322

319323
#[inline]
320-
fn try_from(value: &'a LuaString) -> Result<Self> {
321-
let BorrowedBytes { buf, borrow, _lua } = BorrowedBytes::from(value);
324+
fn try_from(value: &LuaString) -> Result<Self> {
325+
let BorrowedBytes { buf, vref, _lua } = BorrowedBytes::from(value);
322326
let buf =
323327
str::from_utf8(buf).map_err(|e| Error::from_lua_conversion("string", "&str", e.to_string()))?;
324-
Ok(Self { buf, borrow, _lua })
328+
Ok(Self { buf, vref, _lua })
325329
}
326330
}
327331

328332
/// A borrowed byte slice (`&[u8]`) that holds a strong reference to the Lua state.
329-
pub struct BorrowedBytes<'a> {
333+
pub struct BorrowedBytes {
330334
// `buf` points to a readonly memory managed by Lua
331-
pub(crate) buf: &'a [u8],
332-
pub(crate) borrow: Cow<'a, LuaString>,
335+
pub(crate) buf: &'static [u8],
336+
pub(crate) vref: ValueRef,
333337
pub(crate) _lua: Lua,
334338
}
335339

336-
impl Deref for BorrowedBytes<'_> {
340+
impl Deref for BorrowedBytes {
337341
type Target = [u8];
338342

339343
#[inline(always)]
@@ -342,27 +346,27 @@ impl Deref for BorrowedBytes<'_> {
342346
}
343347
}
344348

345-
impl Borrow<[u8]> for BorrowedBytes<'_> {
349+
impl Borrow<[u8]> for BorrowedBytes {
346350
#[inline(always)]
347351
fn borrow(&self) -> &[u8] {
348352
self.buf
349353
}
350354
}
351355

352-
impl AsRef<[u8]> for BorrowedBytes<'_> {
356+
impl AsRef<[u8]> for BorrowedBytes {
353357
#[inline(always)]
354358
fn as_ref(&self) -> &[u8] {
355359
self.buf
356360
}
357361
}
358362

359-
impl fmt::Debug for BorrowedBytes<'_> {
363+
impl fmt::Debug for BorrowedBytes {
360364
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
361365
self.buf.fmt(f)
362366
}
363367
}
364368

365-
impl<T> PartialEq<T> for BorrowedBytes<'_>
369+
impl<T> PartialEq<T> for BorrowedBytes
366370
where
367371
T: AsRef<[u8]>,
368372
{
@@ -371,9 +375,9 @@ where
371375
}
372376
}
373377

374-
impl Eq for BorrowedBytes<'_> {}
378+
impl Eq for BorrowedBytes {}
375379

376-
impl<T> PartialOrd<T> for BorrowedBytes<'_>
380+
impl<T> PartialOrd<T> for BorrowedBytes
377381
where
378382
T: AsRef<[u8]>,
379383
{
@@ -382,13 +386,13 @@ where
382386
}
383387
}
384388

385-
impl Ord for BorrowedBytes<'_> {
389+
impl Ord for BorrowedBytes {
386390
fn cmp(&self, other: &Self) -> cmp::Ordering {
387391
self.buf.cmp(other.buf)
388392
}
389393
}
390394

391-
impl<'a> IntoIterator for &'a BorrowedBytes<'_> {
395+
impl<'a> IntoIterator for &'a BorrowedBytes {
392396
type Item = &'a u8;
393397
type IntoIter = slice::Iter<'a, u8>;
394398

@@ -397,12 +401,14 @@ impl<'a> IntoIterator for &'a BorrowedBytes<'_> {
397401
}
398402
}
399403

400-
impl<'a> From<&'a LuaString> for BorrowedBytes<'a> {
404+
impl From<&LuaString> for BorrowedBytes {
401405
#[inline]
402-
fn from(value: &'a LuaString) -> Self {
406+
fn from(value: &LuaString) -> Self {
403407
let (buf, _lua) = unsafe { value.to_slice() };
404-
let borrow = Cow::Borrowed(value);
405-
Self { buf, borrow, _lua }
408+
let vref = value.0.clone();
409+
// SAFETY: The `buf` is valid for the lifetime of the Lua state and occupied slot index
410+
let buf = unsafe { mem::transmute::<&[u8], &'static [u8]>(buf) };
411+
Self { buf, vref, _lua }
406412
}
407413
}
408414

src/value.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ impl Value {
361361
note = "This method does not follow Rust naming convention. Use `as_string().and_then(|s| s.to_str().ok())` instead."
362362
)]
363363
#[inline]
364-
pub fn as_str(&self) -> Option<BorrowedStr<'_>> {
364+
pub fn as_str(&self) -> Option<BorrowedStr> {
365365
self.as_string().and_then(|s| s.to_str().ok())
366366
}
367367

0 commit comments

Comments
 (0)