Skip to content

Commit

Permalink
impl OsString::leak & PathBuf::leak
Browse files Browse the repository at this point in the history
  • Loading branch information
its-the-shrimp committed Jun 4, 2024
1 parent 6ef46b3 commit 85aa4b6
Show file tree
Hide file tree
Showing 7 changed files with 67 additions and 0 deletions.
19 changes: 19 additions & 0 deletions std/src/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,25 @@ impl OsString {
unsafe { Box::from_raw(rw) }
}

/// Consumes and leaks the `OsString`, returning a mutable reference to the contents,
/// `&'a mut OsStr`.
///
/// The caller has free choice over the returned lifetime, including 'static.
/// Indeed, this function is ideally used for data that lives for the remainder of
/// the program’s life, as dropping the returned reference will cause a memory leak.
///
/// It does not reallocate or shrink the `OsString`, so the leaked allocation may include
/// unused capacity that is not part of the returned slice. If you want to discard excess
/// capacity, call [`into_boxed_os_str`], and then [`Box::leak`] instead.
/// However, keep in mind that trimming the capacity may result in a reallocation and copy.
///
/// [`into_boxed_os_str`]: Self::into_boxed_os_str
#[unstable(feature = "os_string_pathbuf_leak", issue = "125965")]
#[inline]
pub fn leak<'a>(self) -> &'a mut OsStr {
OsStr::from_inner_mut(self.inner.leak())
}

/// Part of a hack to make PathBuf::push/pop more efficient.
#[inline]
pub(crate) fn as_mut_vec_for_path_buf(&mut self) -> &mut Vec<u8> {
Expand Down
7 changes: 7 additions & 0 deletions std/src/ffi/os_str/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ fn test_os_string_clear() {
assert_eq!(0, os_string.inner.as_inner().len());
}

#[test]
fn test_os_string_leak() {
let os_string = OsString::from("have a cake");
let leaked = os_string.leak();
assert_eq!(leaked.as_encoded_bytes(), b"have a cake");
}

#[test]
fn test_os_string_capacity() {
let os_string = OsString::with_capacity(0);
Expand Down
19 changes: 19 additions & 0 deletions std/src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1226,6 +1226,25 @@ impl PathBuf {
self
}

/// Consumes and leaks the `PathBuf`, returning a mutable reference to the contents,
/// `&'a mut Path`.
///
/// The caller has free choice over the returned lifetime, including 'static.
/// Indeed, this function is ideally used for data that lives for the remainder of
/// the program’s life, as dropping the returned reference will cause a memory leak.
///
/// It does not reallocate or shrink the `PathBuf`, so the leaked allocation may include
/// unused capacity that is not part of the returned slice. If you want to discard excess
/// capacity, call [`into_boxed_path`], and then [`Box::leak`] instead.
/// However, keep in mind that trimming the capacity may result in a reallocation and copy.
///
/// [`into_boxed_path`]: Self::into_boxed_path
#[unstable(feature = "os_string_pathbuf_leak", issue = "125965")]
#[inline]
pub fn leak<'a>(self) -> &'a mut Path {
Path::from_inner_mut(self.inner.leak())
}

/// Extends `self` with `path`.
///
/// If `path` is absolute, it replaces the current path.
Expand Down
7 changes: 7 additions & 0 deletions std/src/path/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,13 @@ fn into() {
assert_eq!(static_cow_path, owned_cow_path);
}

#[test]
fn test_pathbuf_leak() {
let buf = PathBuf::from("/have/a/cake".to_owned());
let leaked = buf.leak();
assert_eq!(leaked.as_os_str().as_encoded_bytes(), b"/have/a/cake");
}

#[test]
#[cfg(unix)]
pub fn test_decompositions_unix() {
Expand Down
5 changes: 5 additions & 0 deletions std/src/sys/os_str/bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,11 @@ impl Buf {
self.inner.extend_from_slice(&s.inner)
}

#[inline]
pub fn leak<'a>(self) -> &'a mut Slice {
unsafe { mem::transmute(self.inner.leak()) }
}

#[inline]
pub fn into_box(self) -> Box<Slice> {
unsafe { mem::transmute(self.inner.into_boxed_slice()) }
Expand Down
5 changes: 5 additions & 0 deletions std/src/sys/os_str/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ impl Buf {
self.inner.shrink_to(min_capacity)
}

#[inline]
pub fn leak<'a>(self) -> &'a mut Slice {
unsafe { mem::transmute(self.inner.leak()) }
}

#[inline]
pub fn into_box(self) -> Box<Slice> {
unsafe { mem::transmute(self.inner.into_box()) }
Expand Down
5 changes: 5 additions & 0 deletions std/src/sys_common/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ impl Wtf8Buf {
self.bytes.shrink_to(min_capacity)
}

#[inline]
pub fn leak<'a>(self) -> &'a mut Wtf8 {
unsafe { Wtf8::from_mut_bytes_unchecked(self.bytes.leak()) }
}

/// Returns the number of bytes that this string buffer can hold without reallocating.
#[inline]
pub fn capacity(&self) -> usize {
Expand Down

0 comments on commit 85aa4b6

Please sign in to comment.