diff --git a/crates/std/src/ffi/c_str.rs b/crates/std/src/ffi/c_str.rs index a7d1de4..cb0ca5d 100644 --- a/crates/std/src/ffi/c_str.rs +++ b/crates/std/src/ffi/c_str.rs @@ -1,7 +1,14 @@ //! [`CStr`], [`CString`], and related types. + +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub use alloc::ffi::c_str::FromVecWithNulError; +#[stable(feature = "cstring_into", since = "1.7.0")] pub use alloc::ffi::c_str::IntoStringError; +#[stable(feature = "rust1", since = "1.0.0")] pub use alloc::ffi::c_str::{CString, NulError}; +#[stable(feature = "rust1", since = "1.0.0")] pub use core::ffi::c_str::CStr; +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub use core::ffi::c_str::FromBytesUntilNulError; +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub use core::ffi::c_str::FromBytesWithNulError; diff --git a/crates/std/src/ffi/mod.rs b/crates/std/src/ffi/mod.rs index 7f24b7b..999bd5e 100644 --- a/crates/std/src/ffi/mod.rs +++ b/crates/std/src/ffi/mod.rs @@ -158,27 +158,50 @@ //! [`collect`]: crate::iter::Iterator::collect "iter::Iterator::collect" //! [windows.OsStringExt]: crate::os::windows::ffi::OsStringExt "os::windows::ffi::OsStringExt" //! [`from_wide`]: crate::os::windows::ffi::OsStringExt::from_wide "os::windows::ffi::OsStringExt::from_wide" + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "c_str_module", since = "1.88.0")] pub mod c_str; + +#[stable(feature = "core_c_void", since = "1.30.0")] pub use core::ffi::c_void; +#[unstable( + feature = "c_variadic", + reason = "the `c_variadic` feature has not been properly tested on \ + all supported platforms", + issue = "44930" +)] pub use core::ffi::{VaArgSafe, VaList}; +#[stable(feature = "core_ffi_c", since = "1.64.0")] pub use core::ffi::{ c_char, c_double, c_float, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong, c_ushort, }; +#[unstable(feature = "c_size_t", issue = "88345")] pub use core::ffi::{c_ptrdiff_t, c_size_t, c_ssize_t}; #[doc(inline)] +#[stable(feature = "cstr_from_bytes_until_nul", since = "1.69.0")] pub use self::c_str::FromBytesUntilNulError; #[doc(inline)] +#[stable(feature = "cstr_from_bytes", since = "1.10.0")] pub use self::c_str::FromBytesWithNulError; #[doc(inline)] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] pub use self::c_str::FromVecWithNulError; #[doc(inline)] +#[stable(feature = "cstring_into", since = "1.7.0")] pub use self::c_str::IntoStringError; #[doc(inline)] +#[stable(feature = "rust1", since = "1.0.0")] pub use self::c_str::NulError; #[doc(inline)] +#[stable(feature = "rust1", since = "1.0.0")] pub use self::c_str::{CStr, CString}; -// #[doc(inline)] -// pub use self::os_str::{OsStr, OsString}; +#[stable(feature = "rust1", since = "1.0.0")] +#[doc(inline)] +pub use self::os_str::{OsStr, OsString}; + +#[stable(feature = "os_str_display", since = "1.87.0")] pub mod os_str; diff --git a/crates/std/src/ffi/os_str.rs b/crates/std/src/ffi/os_str.rs index 2862f4f..2b1425f 100644 --- a/crates/std/src/ffi/os_str.rs +++ b/crates/std/src/ffi/os_str.rs @@ -1,1661 +1,1845 @@ -// //! The [`OsStr`] and [`OsString`] types and associated utilities. - -// #[cfg(test)] -// mod tests; - -// use core::clone::CloneToUninit; - -// use crate::borrow::{Borrow, Cow}; -// use crate::collections::TryReserveError; -// use crate::hash::{Hash, Hasher}; -// use crate::ops::{self, Range}; -// use crate::rc::Rc; -// use crate::str::FromStr; -// use crate::sync::Arc; -// use crate::sys::os_str::{Buf, Slice}; -// use crate::sys::{AsInner, FromInner, IntoInner}; -// use crate::{cmp, fmt, slice}; - -// /// A type that can represent owned, mutable platform-native strings, but is -// /// cheaply inter-convertible with Rust strings. -// /// -// /// The need for this type arises from the fact that: -// /// -// /// * On Unix systems, strings are often arbitrary sequences of non-zero -// /// bytes, in many cases interpreted as UTF-8. -// /// -// /// * On Windows, strings are often arbitrary sequences of non-zero 16-bit -// /// values, interpreted as UTF-16 when it is valid to do so. -// /// -// /// * In Rust, strings are always valid UTF-8, which may contain zeros. -// /// -// /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust -// /// and platform-native string values, and in particular allowing a Rust string -// /// to be converted into an "OS" string with no cost if possible. A consequence -// /// of this is that `OsString` instances are *not* `NUL` terminated; in order -// /// to pass to e.g., Unix system call, you should create a [`CStr`]. -// /// -// /// `OsString` is to &[OsStr] as [`String`] is to &[str]: the former -// /// in each pair are owned strings; the latter are borrowed -// /// references. -// /// -// /// Note, `OsString` and [`OsStr`] internally do not necessarily hold strings in -// /// the form native to the platform; While on Unix, strings are stored as a -// /// sequence of 8-bit values, on Windows, where strings are 16-bit value based -// /// as just discussed, strings are also actually stored as a sequence of 8-bit -// /// values, encoded in a less-strict variant of UTF-8. This is useful to -// /// understand when handling capacity and length values. -// /// -// /// # Capacity of `OsString` -// /// -// /// Capacity uses units of UTF-8 bytes for OS strings which were created from valid unicode, and -// /// uses units of bytes in an unspecified encoding for other contents. On a given target, all -// /// `OsString` and `OsStr` values use the same units for capacity, so the following will work: -// /// ``` -// /// use std::ffi::{OsStr, OsString}; -// /// -// /// fn concat_os_strings(a: &OsStr, b: &OsStr) -> OsString { -// /// let mut ret = OsString::with_capacity(a.len() + b.len()); // This will allocate -// /// ret.push(a); // This will not allocate further -// /// ret.push(b); // This will not allocate further -// /// ret -// /// } -// /// ``` -// /// -// /// # Creating an `OsString` -// /// -// /// **From a Rust string**: `OsString` implements -// /// [From]<[String]>, so you can use my_string.[into]\() to -// /// create an `OsString` from a normal Rust string. -// /// -// /// **From slices:** Just like you can start with an empty Rust -// /// [`String`] and then [`String::push_str`] some &[str] -// /// sub-string slices into it, you can create an empty `OsString` with -// /// the [`OsString::new`] method and then push string slices into it with the -// /// [`OsString::push`] method. -// /// -// /// # Extracting a borrowed reference to the whole OS string -// /// -// /// You can use the [`OsString::as_os_str`] method to get an &[OsStr] from -// /// an `OsString`; this is effectively a borrowed reference to the -// /// whole string. -// /// -// /// # Conversions -// /// -// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -// /// the traits which `OsString` implements for [conversions] from/to native representations. -// /// -// /// [`CStr`]: crate::ffi::CStr -// /// [conversions]: super#conversions -// /// [into]: Into::into -// #[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] -// pub struct OsString { -// inner: Buf, -// } - -// /// Allows extension traits within `std`. -// impl crate::sealed::Sealed for OsString {} - -// /// Borrowed reference to an OS string (see [`OsString`]). -// /// -// /// This type represents a borrowed reference to a string in the operating system's preferred -// /// representation. -// /// -// /// `&OsStr` is to [`OsString`] as &[str] is to [`String`]: the -// /// former in each pair are borrowed references; the latter are owned strings. -// /// -// /// See the [module's toplevel documentation about conversions][conversions] for a discussion on -// /// the traits which `OsStr` implements for [conversions] from/to native representations. -// /// -// /// [conversions]: super#conversions -// #[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] -// // `OsStr::from_inner` and `impl CloneToUninit for OsStr` current implementation relies -// // on `OsStr` being layout-compatible with `Slice`. -// // However, `OsStr` layout is considered an implementation detail and must not be relied upon. -// #[repr(transparent)] -// pub struct OsStr { -// inner: Slice, -// } - -// /// Allows extension traits within `std`. -// impl crate::sealed::Sealed for OsStr {} - -// impl OsString { -// /// Constructs a new empty `OsString`. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let os_string = OsString::new(); -// /// ``` -// #[must_use] -// #[inline] -// pub const fn new() -> OsString { -// OsString { inner: Buf::from_string(String::new()) } -// } - -// /// Converts bytes to an `OsString` without checking that the bytes contains -// /// valid [`OsStr`]-encoded data. -// /// -// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. -// /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit -// /// ASCII. -// /// -// /// See the [module's toplevel documentation about conversions][conversions] for safe, -// /// cross-platform [conversions] from/to native representations. -// /// -// /// # Safety -// /// -// /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of -// /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same Rust version -// /// built for the same target platform. For example, reconstructing an `OsString` from bytes sent -// /// over the network or stored in a file will likely violate these safety rules. -// /// -// /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be -// /// split either immediately before or immediately after any valid non-empty UTF-8 substring. -// /// -// /// # Example -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new("Mary had a little lamb"); -// /// let bytes = os_str.as_encoded_bytes(); -// /// let words = bytes.split(|b| *b == b' '); -// /// let words: Vec<&OsStr> = words.map(|word| { -// /// // SAFETY: -// /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes` -// /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring -// /// unsafe { OsStr::from_encoded_bytes_unchecked(word) } -// /// }).collect(); -// /// ``` -// /// -// /// [conversions]: super#conversions -// #[inline] -// pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec) -> Self { -// OsString { inner: unsafe { Buf::from_encoded_bytes_unchecked(bytes) } } -// } - -// /// Converts to an [`OsStr`] slice. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::{OsString, OsStr}; -// /// -// /// let os_string = OsString::from("foo"); -// /// let os_str = OsStr::new("foo"); -// /// assert_eq!(os_string.as_os_str(), os_str); -// /// ``` -// #[cfg_attr(not(test), rustc_diagnostic_item = "os_string_as_os_str")] -// #[must_use] -// #[inline] -// pub fn as_os_str(&self) -> &OsStr { -// self -// } - -// /// Converts the `OsString` into a byte vector. To convert the byte vector back into an -// /// `OsString`, use the [`OsString::from_encoded_bytes_unchecked`] function. -// /// -// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. -// /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit -// /// ASCII. -// /// -// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should -// /// be treated as opaque and only comparable within the same Rust version built for the same -// /// target platform. For example, sending the bytes over the network or storing it in a file -// /// will likely result in incompatible data. See [`OsString`] for more encoding details -// /// and [`std::ffi`] for platform-specific, specified conversions. -// /// -// /// [`std::ffi`]: crate::ffi -// #[inline] -// pub fn into_encoded_bytes(self) -> Vec { -// self.inner.into_encoded_bytes() -// } - -// /// Converts the `OsString` into a [`String`] if it contains valid Unicode data. -// /// -// /// On failure, ownership of the original `OsString` is returned. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let os_string = OsString::from("foo"); -// /// let string = os_string.into_string(); -// /// assert_eq!(string, Ok(String::from("foo"))); -// /// ``` -// #[inline] -// pub fn into_string(self) -> Result { -// self.inner.into_string().map_err(|buf| OsString { inner: buf }) -// } - -// /// Extends the string with the given &[OsStr] slice. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut os_string = OsString::from("foo"); -// /// os_string.push("bar"); -// /// assert_eq!(&os_string, "foobar"); -// /// ``` -// #[inline] -// pub fn push>(&mut self, s: T) { -// trait SpecPushTo { -// fn spec_push_to(&self, buf: &mut OsString); -// } - -// impl> SpecPushTo for T { -// #[inline] -// default fn spec_push_to(&self, buf: &mut OsString) { -// buf.inner.push_slice(&self.as_ref().inner); -// } -// } - -// // Use a more efficient implementation when the string is UTF-8. -// macro spec_str($T:ty) { -// impl SpecPushTo for $T { -// #[inline] -// fn spec_push_to(&self, buf: &mut OsString) { -// buf.inner.push_str(self); -// } -// } -// } -// spec_str!(str); -// spec_str!(String); - -// s.spec_push_to(self) -// } - -// /// Creates a new `OsString` with at least the given capacity. -// /// -// /// The string will be able to hold at least `capacity` length units of other -// /// OS strings without reallocating. This method is allowed to allocate for -// /// more units than `capacity`. If `capacity` is 0, the string will not -// /// allocate. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut os_string = OsString::with_capacity(10); -// /// let capacity = os_string.capacity(); -// /// -// /// // This push is done without reallocating -// /// os_string.push("foo"); -// /// -// /// assert_eq!(capacity, os_string.capacity()); -// /// ``` -// #[must_use] -// #[inline] -// pub fn with_capacity(capacity: usize) -> OsString { -// OsString { inner: Buf::with_capacity(capacity) } -// } - -// /// Truncates the `OsString` to zero length. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut os_string = OsString::from("foo"); -// /// assert_eq!(&os_string, "foo"); -// /// -// /// os_string.clear(); -// /// assert_eq!(&os_string, ""); -// /// ``` -// #[inline] -// pub fn clear(&mut self) { -// self.inner.clear() -// } - -// /// Returns the capacity this `OsString` can hold without reallocating. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let os_string = OsString::with_capacity(10); -// /// assert!(os_string.capacity() >= 10); -// /// ``` -// #[must_use] -// #[inline] -// pub fn capacity(&self) -> usize { -// self.inner.capacity() -// } - -// /// Reserves capacity for at least `additional` more capacity to be inserted -// /// in the given `OsString`. Does nothing if the capacity is -// /// already sufficient. -// /// -// /// The collection may reserve more space to speculatively avoid frequent reallocations. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut s = OsString::new(); -// /// s.reserve(10); -// /// assert!(s.capacity() >= 10); -// /// ``` -// #[inline] -// pub fn reserve(&mut self, additional: usize) { -// self.inner.reserve(additional) -// } - -// /// Tries to reserve capacity for at least `additional` more length units -// /// in the given `OsString`. The string may reserve more space to speculatively avoid -// /// frequent reallocations. After calling `try_reserve`, capacity will be -// /// greater than or equal to `self.len() + additional` if it returns `Ok(())`. -// /// Does nothing if capacity is already sufficient. This method preserves -// /// the contents even if an error occurs. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Errors -// /// -// /// If the capacity overflows, or the allocator reports a failure, then an error -// /// is returned. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::{OsStr, OsString}; -// /// use std::collections::TryReserveError; -// /// -// /// fn process_data(data: &str) -> Result { -// /// let mut s = OsString::new(); -// /// -// /// // Pre-reserve the memory, exiting if we can't -// /// s.try_reserve(OsStr::new(data).len())?; -// /// -// /// // Now we know this can't OOM in the middle of our complex work -// /// s.push(data); -// /// -// /// Ok(s) -// /// } -// /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); -// /// ``` -// #[inline] -// pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { -// self.inner.try_reserve(additional) -// } - -// /// Reserves the minimum capacity for at least `additional` more capacity to -// /// be inserted in the given `OsString`. Does nothing if the capacity is -// /// already sufficient. -// /// -// /// Note that the allocator may give the collection more space than it -// /// requests. Therefore, capacity can not be relied upon to be precisely -// /// minimal. Prefer [`reserve`] if future insertions are expected. -// /// -// /// [`reserve`]: OsString::reserve -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut s = OsString::new(); -// /// s.reserve_exact(10); -// /// assert!(s.capacity() >= 10); -// /// ``` -// #[inline] -// pub fn reserve_exact(&mut self, additional: usize) { -// self.inner.reserve_exact(additional) -// } - -// /// Tries to reserve the minimum capacity for at least `additional` -// /// more length units in the given `OsString`. After calling -// /// `try_reserve_exact`, capacity will be greater than or equal to -// /// `self.len() + additional` if it returns `Ok(())`. -// /// Does nothing if the capacity is already sufficient. -// /// -// /// Note that the allocator may give the `OsString` more space than it -// /// requests. Therefore, capacity can not be relied upon to be precisely -// /// minimal. Prefer [`try_reserve`] if future insertions are expected. -// /// -// /// [`try_reserve`]: OsString::try_reserve -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Errors -// /// -// /// If the capacity overflows, or the allocator reports a failure, then an error -// /// is returned. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::{OsStr, OsString}; -// /// use std::collections::TryReserveError; -// /// -// /// fn process_data(data: &str) -> Result { -// /// let mut s = OsString::new(); -// /// -// /// // Pre-reserve the memory, exiting if we can't -// /// s.try_reserve_exact(OsStr::new(data).len())?; -// /// -// /// // Now we know this can't OOM in the middle of our complex work -// /// s.push(data); -// /// -// /// Ok(s) -// /// } -// /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); -// /// ``` -// #[inline] -// pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { -// self.inner.try_reserve_exact(additional) -// } - -// /// Shrinks the capacity of the `OsString` to match its length. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut s = OsString::from("foo"); -// /// -// /// s.reserve(100); -// /// assert!(s.capacity() >= 100); -// /// -// /// s.shrink_to_fit(); -// /// assert_eq!(3, s.capacity()); -// /// ``` -// #[inline] -// pub fn shrink_to_fit(&mut self) { -// self.inner.shrink_to_fit() -// } - -// /// Shrinks the capacity of the `OsString` with a lower bound. -// /// -// /// The capacity will remain at least as large as both the length -// /// and the supplied value. -// /// -// /// If the current capacity is less than the lower limit, this is a no-op. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut s = OsString::from("foo"); -// /// -// /// s.reserve(100); -// /// assert!(s.capacity() >= 100); -// /// -// /// s.shrink_to(10); -// /// assert!(s.capacity() >= 10); -// /// s.shrink_to(0); -// /// assert!(s.capacity() >= 3); -// /// ``` -// #[inline] -// pub fn shrink_to(&mut self, min_capacity: usize) { -// self.inner.shrink_to(min_capacity) -// } - -// /// Converts this `OsString` into a boxed [`OsStr`]. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::{OsString, OsStr}; -// /// -// /// let s = OsString::from("hello"); -// /// -// /// let b: Box = s.into_boxed_os_str(); -// /// ``` -// #[must_use = "`self` will be dropped if the result is not used"] -// pub fn into_boxed_os_str(self) -> Box { -// let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; -// 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 -// #[inline] -// pub fn leak<'a>(self) -> &'a mut OsStr { -// OsStr::from_inner_mut(self.inner.leak()) -// } - -// /// Truncate the `OsString` to the specified length. -// /// -// /// # Panics -// /// Panics if `len` does not lie on a valid `OsStr` boundary -// /// (as described in [`OsStr::slice_encoded_bytes`]). -// #[inline] -// pub fn truncate(&mut self, len: usize) { -// self.as_os_str().inner.check_public_boundary(len); -// // SAFETY: The length was just checked to be at a valid boundary. -// unsafe { self.inner.truncate_unchecked(len) }; -// } - -// /// Provides plumbing to `Vec::extend_from_slice` without giving full -// /// mutable access to the `Vec`. -// /// -// /// # Safety -// /// -// /// The slice must be valid for the platform encoding (as described in -// /// [`OsStr::from_encoded_bytes_unchecked`]). -// /// -// /// This bypasses the encoding-dependent surrogate joining, so either -// /// `self` must not end with a leading surrogate half, or `other` must not -// /// start with a trailing surrogate half. -// #[inline] -// pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { -// // SAFETY: Guaranteed by caller. -// unsafe { self.inner.extend_from_slice_unchecked(other) }; -// } -// } -// impl From for OsString { -// /// Converts a [`String`] into an [`OsString`]. -// /// -// /// This conversion does not allocate or copy memory. -// #[inline] -// fn from(s: String) -> OsString { -// OsString { inner: Buf::from_string(s) } -// } -// } -// impl> From<&T> for OsString { -// /// Copies any value implementing [AsRef]<[OsStr]> -// /// into a newly allocated [`OsString`]. -// fn from(s: &T) -> OsString { -// trait SpecToOsString { -// fn spec_to_os_string(&self) -> OsString; -// } - -// impl> SpecToOsString for T { -// #[inline] -// default fn spec_to_os_string(&self) -> OsString { -// self.as_ref().to_os_string() -// } -// } - -// // Preserve the known-UTF-8 property for strings. -// macro spec_str($T:ty) { -// impl SpecToOsString for $T { -// #[inline] -// fn spec_to_os_string(&self) -> OsString { -// OsString::from(String::from(self)) -// } -// } -// } -// spec_str!(str); -// spec_str!(String); - -// s.spec_to_os_string() -// } -// } -// impl ops::Index for OsString { -// type Output = OsStr; - -// #[inline] -// fn index(&self, _index: ops::RangeFull) -> &OsStr { -// OsStr::from_inner(self.inner.as_slice()) -// } -// } -// impl ops::IndexMut for OsString { -// #[inline] -// fn index_mut(&mut self, _index: ops::RangeFull) -> &mut OsStr { -// OsStr::from_inner_mut(self.inner.as_mut_slice()) -// } -// } -// impl ops::Deref for OsString { -// type Target = OsStr; - -// #[inline] -// fn deref(&self) -> &OsStr { -// &self[..] -// } -// } -// impl ops::DerefMut for OsString { -// #[inline] -// fn deref_mut(&mut self) -> &mut OsStr { -// &mut self[..] -// } -// } -// impl Default for OsString { -// /// Constructs an empty `OsString`. -// #[inline] -// fn default() -> OsString { -// OsString::new() -// } -// } -// impl Clone for OsString { -// #[inline] -// fn clone(&self) -> Self { -// OsString { inner: self.inner.clone() } -// } - -// /// Clones the contents of `source` into `self`. -// /// -// /// This method is preferred over simply assigning `source.clone()` to `self`, -// /// as it avoids reallocation if possible. -// #[inline] -// fn clone_from(&mut self, source: &Self) { -// self.inner.clone_from(&source.inner) -// } -// } -// impl fmt::Debug for OsString { -// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { -// fmt::Debug::fmt(&**self, formatter) -// } -// } -// impl PartialEq for OsString { -// #[inline] -// fn eq(&self, other: &OsString) -> bool { -// &**self == &**other -// } -// } -// impl PartialEq for OsString { -// #[inline] -// fn eq(&self, other: &str) -> bool { -// &**self == other -// } -// } -// impl PartialEq for str { -// #[inline] -// fn eq(&self, other: &OsString) -> bool { -// &**other == self -// } -// } -// impl PartialEq<&str> for OsString { -// #[inline] -// fn eq(&self, other: &&str) -> bool { -// **self == **other -// } -// } -// impl<'a> PartialEq for &'a str { -// #[inline] -// fn eq(&self, other: &OsString) -> bool { -// **other == **self -// } -// } -// impl Eq for OsString {} -// impl PartialOrd for OsString { -// #[inline] -// fn partial_cmp(&self, other: &OsString) -> Option { -// (&**self).partial_cmp(&**other) -// } -// #[inline] -// fn lt(&self, other: &OsString) -> bool { -// &**self < &**other -// } -// #[inline] -// fn le(&self, other: &OsString) -> bool { -// &**self <= &**other -// } -// #[inline] -// fn gt(&self, other: &OsString) -> bool { -// &**self > &**other -// } -// #[inline] -// fn ge(&self, other: &OsString) -> bool { -// &**self >= &**other -// } -// } -// impl PartialOrd for OsString { -// #[inline] -// fn partial_cmp(&self, other: &str) -> Option { -// (&**self).partial_cmp(other) -// } -// } -// impl Ord for OsString { -// #[inline] -// fn cmp(&self, other: &OsString) -> cmp::Ordering { -// (&**self).cmp(&**other) -// } -// } -// impl Hash for OsString { -// #[inline] -// fn hash(&self, state: &mut H) { -// (&**self).hash(state) -// } -// } -// impl fmt::Write for OsString { -// fn write_str(&mut self, s: &str) -> fmt::Result { -// self.push(s); -// Ok(()) -// } -// } - -// impl OsStr { -// /// Coerces into an `OsStr` slice. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new("foo"); -// /// ``` -// #[inline] -// pub const fn new + ?Sized>(s: &S) -> &OsStr { -// s.as_ref() -// } - -// /// Converts a slice of bytes to an OS string slice without checking that the string contains -// /// valid `OsStr`-encoded data. -// /// -// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. -// /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit -// /// ASCII. -// /// -// /// See the [module's toplevel documentation about conversions][conversions] for safe, -// /// cross-platform [conversions] from/to native representations. -// /// -// /// # Safety -// /// -// /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of -// /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same Rust version -// /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent -// /// over the network or stored in a file will likely violate these safety rules. -// /// -// /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be -// /// split either immediately before or immediately after any valid non-empty UTF-8 substring. -// /// -// /// # Example -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new("Mary had a little lamb"); -// /// let bytes = os_str.as_encoded_bytes(); -// /// let words = bytes.split(|b| *b == b' '); -// /// let words: Vec<&OsStr> = words.map(|word| { -// /// // SAFETY: -// /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes` -// /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring -// /// unsafe { OsStr::from_encoded_bytes_unchecked(word) } -// /// }).collect(); -// /// ``` -// /// -// /// [conversions]: super#conversions -// #[inline] -// pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self { -// Self::from_inner(unsafe { Slice::from_encoded_bytes_unchecked(bytes) }) -// } - -// #[inline] -// const fn from_inner(inner: &Slice) -> &OsStr { -// // SAFETY: OsStr is just a wrapper of Slice, -// // therefore converting &Slice to &OsStr is safe. -// unsafe { &*(inner as *const Slice as *const OsStr) } -// } - -// #[inline] -// const fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { -// // SAFETY: OsStr is just a wrapper of Slice, -// // therefore converting &mut Slice to &mut OsStr is safe. -// // Any method that mutates OsStr must be careful not to -// // break platform-specific encoding, in particular Wtf8 on Windows. -// unsafe { &mut *(inner as *mut Slice as *mut OsStr) } -// } - -// /// Yields a &[str] slice if the `OsStr` is valid Unicode. -// /// -// /// This conversion may entail doing a check for UTF-8 validity. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new("foo"); -// /// assert_eq!(os_str.to_str(), Some("foo")); -// /// ``` -// #[must_use = "this returns the result of the operation, \ -// without modifying the original"] -// #[inline] -// pub fn to_str(&self) -> Option<&str> { -// self.inner.to_str().ok() -// } - -// /// Converts an `OsStr` to a [Cow]<[str]>. -// /// -// /// Any non-UTF-8 sequences are replaced with -// /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. -// /// -// /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER -// /// -// /// # Examples -// /// -// /// Calling `to_string_lossy` on an `OsStr` with invalid unicode: -// /// -// /// ``` -// /// // Note, due to differences in how Unix and Windows represent strings, -// /// // we are forced to complicate this example, setting up example `OsStr`s -// /// // with different source data and via different platform extensions. -// /// // Understand that in reality you could end up with such example invalid -// /// // sequences simply through collecting user command line arguments, for -// /// // example. -// /// -// /// #[cfg(unix)] { -// /// use std::ffi::OsStr; -// /// use std::os::unix::ffi::OsStrExt; -// /// -// /// // Here, the values 0x66 and 0x6f correspond to 'f' and 'o' -// /// // respectively. The value 0x80 is a lone continuation byte, invalid -// /// // in a UTF-8 sequence. -// /// let source = [0x66, 0x6f, 0x80, 0x6f]; -// /// let os_str = OsStr::from_bytes(&source[..]); -// /// -// /// assert_eq!(os_str.to_string_lossy(), "fo�o"); -// /// } -// /// #[cfg(windows)] { -// /// use std::ffi::OsString; -// /// use std::os::windows::prelude::*; -// /// -// /// // Here the values 0x0066 and 0x006f correspond to 'f' and 'o' -// /// // respectively. The value 0xD800 is a lone surrogate half, invalid -// /// // in a UTF-16 sequence. -// /// let source = [0x0066, 0x006f, 0xD800, 0x006f]; -// /// let os_string = OsString::from_wide(&source[..]); -// /// let os_str = os_string.as_os_str(); -// /// -// /// assert_eq!(os_str.to_string_lossy(), "fo�o"); -// /// } -// /// ``` -// #[must_use = "this returns the result of the operation, \ -// without modifying the original"] -// #[inline] -// pub fn to_string_lossy(&self) -> Cow<'_, str> { -// self.inner.to_string_lossy() -// } - -// /// Copies the slice into an owned [`OsString`]. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::{OsStr, OsString}; -// /// -// /// let os_str = OsStr::new("foo"); -// /// let os_string = os_str.to_os_string(); -// /// assert_eq!(os_string, OsString::from("foo")); -// /// ``` -// #[must_use = "this returns the result of the operation, \ -// without modifying the original"] -// #[inline] -// #[cfg_attr(not(test), rustc_diagnostic_item = "os_str_to_os_string")] -// pub fn to_os_string(&self) -> OsString { -// OsString { inner: self.inner.to_owned() } -// } - -// /// Checks whether the `OsStr` is empty. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new(""); -// /// assert!(os_str.is_empty()); -// /// -// /// let os_str = OsStr::new("foo"); -// /// assert!(!os_str.is_empty()); -// /// ``` -// #[must_use] -// #[inline] -// pub fn is_empty(&self) -> bool { -// self.inner.inner.is_empty() -// } - -// /// Returns the length of this `OsStr`. -// /// -// /// Note that this does **not** return the number of bytes in the string in -// /// OS string form. -// /// -// /// The length returned is that of the underlying storage used by `OsStr`. -// /// As discussed in the [`OsString`] introduction, [`OsString`] and `OsStr` -// /// store strings in a form best suited for cheap inter-conversion between -// /// native-platform and Rust string forms, which may differ significantly -// /// from both of them, including in storage size and encoding. -// /// -// /// This number is simply useful for passing to other methods, like -// /// [`OsString::with_capacity`] to avoid reallocations. -// /// -// /// See the main `OsString` documentation information about encoding and capacity units. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new(""); -// /// assert_eq!(os_str.len(), 0); -// /// -// /// let os_str = OsStr::new("foo"); -// /// assert_eq!(os_str.len(), 3); -// /// ``` -// #[must_use] -// #[inline] -// pub fn len(&self) -> usize { -// self.inner.inner.len() -// } - -// /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or allocating. -// #[must_use = "`self` will be dropped if the result is not used"] -// pub fn into_os_string(self: Box) -> OsString { -// let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; -// OsString { inner: Buf::from_box(boxed) } -// } - -// /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS -// /// string slice, use the [`OsStr::from_encoded_bytes_unchecked`] function. -// /// -// /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. -// /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit -// /// ASCII. -// /// -// /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should -// /// be treated as opaque and only comparable within the same Rust version built for the same -// /// target platform. For example, sending the slice over the network or storing it in a file -// /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details -// /// and [`std::ffi`] for platform-specific, specified conversions. -// /// -// /// [`std::ffi`]: crate::ffi -// #[inline] -// pub fn as_encoded_bytes(&self) -> &[u8] { -// self.inner.as_encoded_bytes() -// } - -// /// Takes a substring based on a range that corresponds to the return value of -// /// [`OsStr::as_encoded_bytes`]. -// /// -// /// The range's start and end must lie on valid `OsStr` boundaries. -// /// A valid `OsStr` boundary is one of: -// /// - The start of the string -// /// - The end of the string -// /// - Immediately before a valid non-empty UTF-8 substring -// /// - Immediately after a valid non-empty UTF-8 substring -// /// -// /// # Panics -// /// -// /// Panics if `range` does not lie on valid `OsStr` boundaries or if it -// /// exceeds the end of the string. -// /// -// /// # Example -// /// -// /// ``` -// /// #![feature(os_str_slice)] -// /// -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new("foo=bar"); -// /// let bytes = os_str.as_encoded_bytes(); -// /// if let Some(index) = bytes.iter().position(|b| *b == b'=') { -// /// let key = os_str.slice_encoded_bytes(..index); -// /// let value = os_str.slice_encoded_bytes(index + 1..); -// /// assert_eq!(key, "foo"); -// /// assert_eq!(value, "bar"); -// /// } -// /// ``` -// pub fn slice_encoded_bytes>(&self, range: R) -> &Self { -// let encoded_bytes = self.as_encoded_bytes(); -// let Range { start, end } = slice::range(range, ..encoded_bytes.len()); - -// // `check_public_boundary` should panic if the index does not lie on an -// // `OsStr` boundary as described above. It's possible to do this in an -// // encoding-agnostic way, but details of the internal encoding might -// // permit a more efficient implementation. -// self.inner.check_public_boundary(start); -// self.inner.check_public_boundary(end); - -// // SAFETY: `slice::range` ensures that `start` and `end` are valid -// let slice = unsafe { encoded_bytes.get_unchecked(start..end) }; - -// // SAFETY: `slice` comes from `self` and we validated the boundaries -// unsafe { Self::from_encoded_bytes_unchecked(slice) } -// } - -// /// Converts this string to its ASCII lower case equivalent in-place. -// /// -// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', -// /// but non-ASCII letters are unchanged. -// /// -// /// To return a new lowercased value without modifying the existing one, use -// /// [`OsStr::to_ascii_lowercase`]. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut s = OsString::from("GRÜßE, JÜRGEN ❤"); -// /// -// /// s.make_ascii_lowercase(); -// /// -// /// assert_eq!("grÜße, jÜrgen ❤", s); -// /// ``` -// #[inline] -// pub fn make_ascii_lowercase(&mut self) { -// self.inner.make_ascii_lowercase() -// } - -// /// Converts this string to its ASCII upper case equivalent in-place. -// /// -// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', -// /// but non-ASCII letters are unchanged. -// /// -// /// To return a new uppercased value without modifying the existing one, use -// /// [`OsStr::to_ascii_uppercase`]. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let mut s = OsString::from("Grüße, Jürgen ❤"); -// /// -// /// s.make_ascii_uppercase(); -// /// -// /// assert_eq!("GRüßE, JüRGEN ❤", s); -// /// ``` -// #[inline] -// pub fn make_ascii_uppercase(&mut self) { -// self.inner.make_ascii_uppercase() -// } - -// /// Returns a copy of this string where each character is mapped to its -// /// ASCII lower case equivalent. -// /// -// /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', -// /// but non-ASCII letters are unchanged. -// /// -// /// To lowercase the value in-place, use [`OsStr::make_ascii_lowercase`]. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// let s = OsString::from("Grüße, Jürgen ❤"); -// /// -// /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase()); -// /// ``` -// #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase`"] -// pub fn to_ascii_lowercase(&self) -> OsString { -// OsString::from_inner(self.inner.to_ascii_lowercase()) -// } - -// /// Returns a copy of this string where each character is mapped to its -// /// ASCII upper case equivalent. -// /// -// /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', -// /// but non-ASCII letters are unchanged. -// /// -// /// To uppercase the value in-place, use [`OsStr::make_ascii_uppercase`]. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// let s = OsString::from("Grüße, Jürgen ❤"); -// /// -// /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase()); -// /// ``` -// #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase`"] -// pub fn to_ascii_uppercase(&self) -> OsString { -// OsString::from_inner(self.inner.to_ascii_uppercase()) -// } - -// /// Checks if all characters in this string are within the ASCII range. -// /// -// /// An empty string returns `true`. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// let ascii = OsString::from("hello!\n"); -// /// let non_ascii = OsString::from("Grüße, Jürgen ❤"); -// /// -// /// assert!(ascii.is_ascii()); -// /// assert!(!non_ascii.is_ascii()); -// /// ``` -// #[must_use] -// #[inline] -// pub fn is_ascii(&self) -> bool { -// self.inner.is_ascii() -// } - -// /// Checks that two strings are an ASCII case-insensitive match. -// /// -// /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, -// /// but without allocating and copying temporaries. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsString; -// /// -// /// assert!(OsString::from("Ferris").eq_ignore_ascii_case("FERRIS")); -// /// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); -// /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); -// /// ``` -// pub fn eq_ignore_ascii_case>(&self, other: S) -> bool { -// self.inner.eq_ignore_ascii_case(&other.as_ref().inner) -// } - -// /// Returns an object that implements [`Display`] for safely printing an -// /// [`OsStr`] that may contain non-Unicode data. This may perform lossy -// /// conversion, depending on the platform. If you would like an -// /// implementation which escapes the [`OsStr`] please use [`Debug`] -// /// instead. -// /// -// /// [`Display`]: fmt::Display -// /// [`Debug`]: fmt::Debug -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let s = OsStr::new("Hello, world!"); -// /// println!("{}", s.display()); -// /// ``` -// #[must_use = "this does not display the `OsStr`; \ -// it returns an object that can be displayed"] -// #[inline] -// pub fn display(&self) -> Display<'_> { -// Display { os_str: self } -// } - -// /// Returns the same string as a string slice `&OsStr`. -// /// -// /// This method is redundant when used directly on `&OsStr`, but -// /// it helps dereferencing other string-like types to string slices, -// /// for example references to `Box` or `Arc`. -// #[inline] -// pub const fn as_os_str(&self) -> &OsStr { -// self -// } -// } -// impl From<&OsStr> for Box { -// /// Copies the string into a newly allocated [Box]<[OsStr]>. -// #[inline] -// fn from(s: &OsStr) -> Box { -// Box::clone_from_ref(s) -// } -// } -// impl From<&mut OsStr> for Box { -// /// Copies the string into a newly allocated [Box]<[OsStr]>. -// #[inline] -// fn from(s: &mut OsStr) -> Box { -// Self::from(&*s) -// } -// } -// impl From> for Box { -// /// Converts a `Cow<'a, OsStr>` into a [Box]<[OsStr]>, -// /// by copying the contents if they are borrowed. -// #[inline] -// fn from(cow: Cow<'_, OsStr>) -> Box { -// match cow { -// Cow::Borrowed(s) => Box::from(s), -// Cow::Owned(s) => Box::from(s), -// } -// } -// } -// impl From> for OsString { -// /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or -// /// allocating. -// #[inline] -// fn from(boxed: Box) -> OsString { -// boxed.into_os_string() -// } -// } -// impl From for Box { -// /// Converts an [`OsString`] into a [Box]<[OsStr]> without copying or allocating. -// #[inline] -// fn from(s: OsString) -> Box { -// s.into_boxed_os_str() -// } -// } -// impl Clone for Box { -// #[inline] -// fn clone(&self) -> Self { -// self.to_os_string().into_boxed_os_str() -// } -// } -// unsafe impl CloneToUninit for OsStr { -// #[inline] -// #[cfg_attr(debug_assertions, track_caller)] -// unsafe fn clone_to_uninit(&self, dst: *mut u8) { -// // SAFETY: we're just a transparent wrapper around a platform-specific Slice -// unsafe { self.inner.clone_to_uninit(dst) } -// } -// } -// impl From for Arc { -// /// Converts an [`OsString`] into an [Arc]<[OsStr]> by moving the [`OsString`] -// /// data into a new [`Arc`] buffer. -// #[inline] -// fn from(s: OsString) -> Arc { -// let arc = s.inner.into_arc(); -// unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } -// } -// } -// impl From<&OsStr> for Arc { -// /// Copies the string into a newly allocated [Arc]<[OsStr]>. -// #[inline] -// fn from(s: &OsStr) -> Arc { -// let arc = s.inner.into_arc(); -// unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } -// } -// } -// impl From<&mut OsStr> for Arc { -// /// Copies the string into a newly allocated [Arc]<[OsStr]>. -// #[inline] -// fn from(s: &mut OsStr) -> Arc { -// Arc::from(&*s) -// } -// } -// impl From for Rc { -// /// Converts an [`OsString`] into an [Rc]<[OsStr]> by moving the [`OsString`] -// /// data into a new [`Rc`] buffer. -// #[inline] -// fn from(s: OsString) -> Rc { -// let rc = s.inner.into_rc(); -// unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } -// } -// } -// impl From<&OsStr> for Rc { -// /// Copies the string into a newly allocated [Rc]<[OsStr]>. -// #[inline] -// fn from(s: &OsStr) -> Rc { -// let rc = s.inner.into_rc(); -// unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } -// } -// } -// impl From<&mut OsStr> for Rc { -// /// Copies the string into a newly allocated [Rc]<[OsStr]>. -// #[inline] -// fn from(s: &mut OsStr) -> Rc { -// Rc::from(&*s) -// } -// } -// impl<'a> From for Cow<'a, OsStr> { -// /// Moves the string into a [`Cow::Owned`]. -// #[inline] -// fn from(s: OsString) -> Cow<'a, OsStr> { -// Cow::Owned(s) -// } -// } -// impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { -// /// Converts the string reference into a [`Cow::Borrowed`]. -// #[inline] -// fn from(s: &'a OsStr) -> Cow<'a, OsStr> { -// Cow::Borrowed(s) -// } -// } -// impl<'a> From<&'a OsString> for Cow<'a, OsStr> { -// /// Converts the string reference into a [`Cow::Borrowed`]. -// #[inline] -// fn from(s: &'a OsString) -> Cow<'a, OsStr> { -// Cow::Borrowed(s.as_os_str()) -// } -// } -// impl<'a> From> for OsString { -// /// Converts a `Cow<'a, OsStr>` into an [`OsString`], -// /// by copying the contents if they are borrowed. -// #[inline] -// fn from(s: Cow<'a, OsStr>) -> Self { -// s.into_owned() -// } -// } -// impl<'a> TryFrom<&'a OsStr> for &'a str { -// type Error = crate::str::Utf8Error; - -// /// Tries to convert an `&OsStr` to a `&str`. -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let os_str = OsStr::new("foo"); -// /// let as_str = <&str>::try_from(os_str).unwrap(); -// /// assert_eq!(as_str, "foo"); -// /// ``` -// fn try_from(value: &'a OsStr) -> Result { -// value.inner.to_str() -// } -// } -// impl Default for Box { -// #[inline] -// fn default() -> Box { -// let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr; -// unsafe { Box::from_raw(rw) } -// } -// } -// impl Default for &OsStr { -// /// Creates an empty `OsStr`. -// #[inline] -// fn default() -> Self { -// OsStr::new("") -// } -// } -// impl PartialEq for OsStr { -// #[inline] -// fn eq(&self, other: &OsStr) -> bool { -// self.as_encoded_bytes().eq(other.as_encoded_bytes()) -// } -// } -// impl PartialEq for OsStr { -// #[inline] -// fn eq(&self, other: &str) -> bool { -// *self == *OsStr::new(other) -// } -// } -// impl PartialEq for str { -// #[inline] -// fn eq(&self, other: &OsStr) -> bool { -// *other == *OsStr::new(self) -// } -// } -// impl Eq for OsStr {} -// impl PartialOrd for OsStr { -// #[inline] -// fn partial_cmp(&self, other: &OsStr) -> Option { -// self.as_encoded_bytes().partial_cmp(other.as_encoded_bytes()) -// } -// #[inline] -// fn lt(&self, other: &OsStr) -> bool { -// self.as_encoded_bytes().lt(other.as_encoded_bytes()) -// } -// #[inline] -// fn le(&self, other: &OsStr) -> bool { -// self.as_encoded_bytes().le(other.as_encoded_bytes()) -// } -// #[inline] -// fn gt(&self, other: &OsStr) -> bool { -// self.as_encoded_bytes().gt(other.as_encoded_bytes()) -// } -// #[inline] -// fn ge(&self, other: &OsStr) -> bool { -// self.as_encoded_bytes().ge(other.as_encoded_bytes()) -// } -// } -// impl PartialOrd for OsStr { -// #[inline] -// fn partial_cmp(&self, other: &str) -> Option { -// self.partial_cmp(OsStr::new(other)) -// } -// } - -// // FIXME (#19470): cannot provide PartialOrd for str until we -// // have more flexible coherence rules. -// impl Ord for OsStr { -// #[inline] -// fn cmp(&self, other: &OsStr) -> cmp::Ordering { -// self.as_encoded_bytes().cmp(other.as_encoded_bytes()) -// } -// } - -// macro_rules! impl_cmp { -// ($lhs:ty, $rhs: ty) => { -// impl PartialEq<$rhs> for $lhs { -// #[inline] -// fn eq(&self, other: &$rhs) -> bool { -// ::eq(self, other) -// } -// } -// impl PartialEq<$lhs> for $rhs { -// #[inline] -// fn eq(&self, other: &$lhs) -> bool { -// ::eq(self, other) -// } -// } -// impl PartialOrd<$rhs> for $lhs { -// #[inline] -// fn partial_cmp(&self, other: &$rhs) -> Option { -// ::partial_cmp(self, other) -// } -// } -// impl PartialOrd<$lhs> for $rhs { -// #[inline] -// fn partial_cmp(&self, other: &$lhs) -> Option { -// ::partial_cmp(self, other) -// } -// } -// }; -// } - -// impl_cmp!(OsString, OsStr); -// impl_cmp!(OsString, &OsStr); -// impl_cmp!(Cow<'_, OsStr>, OsStr); -// impl_cmp!(Cow<'_, OsStr>, &OsStr); -// impl_cmp!(Cow<'_, OsStr>, OsString); -// impl Hash for OsStr { -// #[inline] -// fn hash(&self, state: &mut H) { -// self.as_encoded_bytes().hash(state) -// } -// } -// impl fmt::Debug for OsStr { -// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { -// fmt::Debug::fmt(&self.inner, formatter) -// } -// } - -// /// Helper struct for safely printing an [`OsStr`] with [`format!`] and `{}`. -// /// -// /// An [`OsStr`] might contain non-Unicode data. This `struct` implements the -// /// [`Display`] trait in a way that mitigates that. It is created by the -// /// [`display`](OsStr::display) method on [`OsStr`]. This may perform lossy -// /// conversion, depending on the platform. If you would like an implementation -// /// which escapes the [`OsStr`] please use [`Debug`] instead. -// /// -// /// # Examples -// /// -// /// ``` -// /// use std::ffi::OsStr; -// /// -// /// let s = OsStr::new("Hello, world!"); -// /// println!("{}", s.display()); -// /// ``` -// /// -// /// [`Display`]: fmt::Display -// /// [`format!`]: crate::format -// pub struct Display<'a> { -// os_str: &'a OsStr, -// } -// impl fmt::Debug for Display<'_> { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// fmt::Debug::fmt(&self.os_str, f) -// } -// } -// impl fmt::Display for Display<'_> { -// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { -// fmt::Display::fmt(&self.os_str.inner, f) -// } -// } -// impl> alloc::slice::Join<&OsStr> for [S] { -// type Output = OsString; - -// fn join(slice: &Self, sep: &OsStr) -> OsString { -// let Some((first, suffix)) = slice.split_first() else { -// return OsString::new(); -// }; -// let first_owned = first.borrow().to_owned(); -// suffix.iter().fold(first_owned, |mut a, b| { -// a.push(sep); -// a.push(b.borrow()); -// a -// }) -// } -// } -// impl Borrow for OsString { -// #[inline] -// fn borrow(&self) -> &OsStr { -// &self[..] -// } -// } -// impl ToOwned for OsStr { -// type Owned = OsString; -// #[inline] -// fn to_owned(&self) -> OsString { -// self.to_os_string() -// } -// #[inline] -// fn clone_into(&self, target: &mut OsString) { -// self.inner.clone_into(&mut target.inner) -// } -// } -// impl const AsRef for OsStr { -// #[inline] -// fn as_ref(&self) -> &OsStr { -// self -// } -// } -// impl AsRef for OsString { -// #[inline] -// fn as_ref(&self) -> &OsStr { -// self -// } -// } -// impl AsRef for str { -// #[inline] -// fn as_ref(&self) -> &OsStr { -// OsStr::from_inner(Slice::from_str(self)) -// } -// } -// impl AsRef for String { -// #[inline] -// fn as_ref(&self) -> &OsStr { -// (&**self).as_ref() -// } -// } - -// impl FromInner for OsString { -// #[inline] -// fn from_inner(buf: Buf) -> OsString { -// OsString { inner: buf } -// } -// } - -// impl IntoInner for OsString { -// #[inline] -// fn into_inner(self) -> Buf { -// self.inner -// } -// } - -// impl AsInner for OsStr { -// #[inline] -// fn as_inner(&self) -> &Slice { -// &self.inner -// } -// } -// impl FromStr for OsString { -// type Err = core::convert::Infallible; - -// #[inline] -// fn from_str(s: &str) -> Result { -// Ok(OsString::from(s)) -// } -// } -// impl Extend for OsString { -// #[inline] -// fn extend>(&mut self, iter: T) { -// for s in iter { -// self.push(&s); -// } -// } -// } -// impl<'a> Extend<&'a OsStr> for OsString { -// #[inline] -// fn extend>(&mut self, iter: T) { -// for s in iter { -// self.push(s); -// } -// } -// } -// impl<'a> Extend> for OsString { -// #[inline] -// fn extend>>(&mut self, iter: T) { -// for s in iter { -// self.push(&s); -// } -// } -// } -// impl FromIterator for OsString { -// #[inline] -// fn from_iter>(iter: I) -> Self { -// let mut iterator = iter.into_iter(); - -// // Because we're iterating over `OsString`s, we can avoid at least -// // one allocation by getting the first string from the iterator -// // and appending to it all the subsequent strings. -// match iterator.next() { -// None => OsString::new(), -// Some(mut buf) => { -// buf.extend(iterator); -// buf -// } -// } -// } -// } -// impl<'a> FromIterator<&'a OsStr> for OsString { -// #[inline] -// fn from_iter>(iter: I) -> Self { -// let mut buf = Self::new(); -// for s in iter { -// buf.push(s); -// } -// buf -// } -// } -// impl<'a> FromIterator> for OsString { -// #[inline] -// fn from_iter>>(iter: I) -> Self { -// let mut iterator = iter.into_iter(); - -// // Because we're iterating over `OsString`s, we can avoid at least -// // one allocation by getting the first owned string from the iterator -// // and appending to it all the subsequent strings. -// match iterator.next() { -// None => OsString::new(), -// Some(Cow::Owned(mut buf)) => { -// buf.extend(iterator); -// buf -// } -// Some(Cow::Borrowed(buf)) => { -// let mut buf = OsString::from(buf); -// buf.extend(iterator); -// buf -// } -// } -// } -// } +//! The [`OsStr`] and [`OsString`] types and associated utilities. + +#[cfg(test)] +mod tests; + +use core::clone::CloneToUninit; + +use crate::borrow::{Borrow, Cow}; +use alloc::collections::TryReserveError; +use crate::hash::{Hash, Hasher}; +use crate::ops::{self, Range}; +use crate::rc::Rc; +use crate::str::FromStr; +use alloc::sync::Arc; +use crate::sys::os_str::{Buf, Slice}; +use crate::sys::{AsInner, FromInner, IntoInner}; +use crate::{cmp, fmt, slice}; + +/// A type that can represent owned, mutable platform-native strings, but is +/// cheaply inter-convertible with Rust strings. +/// +/// The need for this type arises from the fact that: +/// +/// * On Unix systems, strings are often arbitrary sequences of non-zero +/// bytes, in many cases interpreted as UTF-8. +/// +/// * On Windows, strings are often arbitrary sequences of non-zero 16-bit +/// values, interpreted as UTF-16 when it is valid to do so. +/// +/// * In Rust, strings are always valid UTF-8, which may contain zeros. +/// +/// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust +/// and platform-native string values, and in particular allowing a Rust string +/// to be converted into an "OS" string with no cost if possible. A consequence +/// of this is that `OsString` instances are *not* `NUL` terminated; in order +/// to pass to e.g., Unix system call, you should create a [`CStr`]. +/// +/// `OsString` is to &[OsStr] as [`String`] is to &[str]: the former +/// in each pair are owned strings; the latter are borrowed +/// references. +/// +/// Note, `OsString` and [`OsStr`] internally do not necessarily hold strings in +/// the form native to the platform; While on Unix, strings are stored as a +/// sequence of 8-bit values, on Windows, where strings are 16-bit value based +/// as just discussed, strings are also actually stored as a sequence of 8-bit +/// values, encoded in a less-strict variant of UTF-8. This is useful to +/// understand when handling capacity and length values. +/// +/// # Capacity of `OsString` +/// +/// Capacity uses units of UTF-8 bytes for OS strings which were created from valid unicode, and +/// uses units of bytes in an unspecified encoding for other contents. On a given target, all +/// `OsString` and `OsStr` values use the same units for capacity, so the following will work: +/// ``` +/// use std::ffi::{OsStr, OsString}; +/// +/// fn concat_os_strings(a: &OsStr, b: &OsStr) -> OsString { +/// let mut ret = OsString::with_capacity(a.len() + b.len()); // This will allocate +/// ret.push(a); // This will not allocate further +/// ret.push(b); // This will not allocate further +/// ret +/// } +/// ``` +/// +/// # Creating an `OsString` +/// +/// **From a Rust string**: `OsString` implements +/// [From]<[String]>, so you can use my_string.[into]\() to +/// create an `OsString` from a normal Rust string. +/// +/// **From slices:** Just like you can start with an empty Rust +/// [`String`] and then [`String::push_str`] some &[str] +/// sub-string slices into it, you can create an empty `OsString` with +/// the [`OsString::new`] method and then push string slices into it with the +/// [`OsString::push`] method. +/// +/// # Extracting a borrowed reference to the whole OS string +/// +/// You can use the [`OsString::as_os_str`] method to get an &[OsStr] from +/// an `OsString`; this is effectively a borrowed reference to the +/// whole string. +/// +/// # Conversions +/// +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on +/// the traits which `OsString` implements for [conversions] from/to native representations. +/// +/// [`CStr`]: crate::ffi::CStr +/// [conversions]: super#conversions +/// [into]: Into::into +#[cfg_attr(not(test), rustc_diagnostic_item = "OsString")] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct OsString { + inner: Buf, +} + +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for OsString {} + +/// Borrowed reference to an OS string (see [`OsString`]). +/// +/// This type represents a borrowed reference to a string in the operating system's preferred +/// representation. +/// +/// `&OsStr` is to [`OsString`] as &[str] is to [`String`]: the +/// former in each pair are borrowed references; the latter are owned strings. +/// +/// See the [module's toplevel documentation about conversions][conversions] for a discussion on +/// the traits which `OsStr` implements for [conversions] from/to native representations. +/// +/// [conversions]: super#conversions +#[cfg_attr(not(test), rustc_diagnostic_item = "OsStr")] +#[stable(feature = "rust1", since = "1.0.0")] +// `OsStr::from_inner` and `impl CloneToUninit for OsStr` current implementation relies +// on `OsStr` being layout-compatible with `Slice`. +// However, `OsStr` layout is considered an implementation detail and must not be relied upon. +#[repr(transparent)] +pub struct OsStr { + inner: Slice, +} + +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for OsStr {} + +impl OsString { + /// Constructs a new empty `OsString`. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let os_string = OsString::new(); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + #[rustc_const_stable(feature = "const_pathbuf_osstring_new", since = "1.91.0")] + pub const fn new() -> OsString { + OsString { inner: Buf::from_string(String::new()) } + } + + /// Converts bytes to an `OsString` without checking that the bytes contains + /// valid [`OsStr`]-encoded data. + /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// + /// See the [module's toplevel documentation about conversions][conversions] for safe, + /// cross-platform [conversions] from/to native representations. + /// + /// # Safety + /// + /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of + /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same Rust version + /// built for the same target platform. For example, reconstructing an `OsString` from bytes sent + /// over the network or stored in a file will likely violate these safety rules. + /// + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be + /// split either immediately before or immediately after any valid non-empty UTF-8 substring. + /// + /// # Example + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("Mary had a little lamb"); + /// let bytes = os_str.as_encoded_bytes(); + /// let words = bytes.split(|b| *b == b' '); + /// let words: Vec<&OsStr> = words.map(|word| { + /// // SAFETY: + /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes` + /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring + /// unsafe { OsStr::from_encoded_bytes_unchecked(word) } + /// }).collect(); + /// ``` + /// + /// [conversions]: super#conversions + #[inline] + #[stable(feature = "os_str_bytes", since = "1.74.0")] + pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec) -> Self { + OsString { inner: unsafe { Buf::from_encoded_bytes_unchecked(bytes) } } + } + + /// Converts to an [`OsStr`] slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsString, OsStr}; + /// + /// let os_string = OsString::from("foo"); + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_string.as_os_str(), os_str); + /// ``` + #[cfg_attr(not(test), rustc_diagnostic_item = "os_string_as_os_str")] + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use] + #[inline] + pub fn as_os_str(&self) -> &OsStr { + self + } + + /// Converts the `OsString` into a byte vector. To convert the byte vector back into an + /// `OsString`, use the [`OsString::from_encoded_bytes_unchecked`] function. + /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// + /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should + /// be treated as opaque and only comparable within the same Rust version built for the same + /// target platform. For example, sending the bytes over the network or storing it in a file + /// will likely result in incompatible data. See [`OsString`] for more encoding details + /// and [`std::ffi`] for platform-specific, specified conversions. + /// + /// [`std::ffi`]: crate::ffi + #[inline] + #[stable(feature = "os_str_bytes", since = "1.74.0")] + pub fn into_encoded_bytes(self) -> Vec { + self.inner.into_encoded_bytes() + } + + /// Converts the `OsString` into a [`String`] if it contains valid Unicode data. + /// + /// On failure, ownership of the original `OsString` is returned. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let os_string = OsString::from("foo"); + /// let string = os_string.into_string(); + /// assert_eq!(string, Ok(String::from("foo"))); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + pub fn into_string(self) -> Result { + self.inner.into_string().map_err(|buf| OsString { inner: buf }) + } + + /// Extends the string with the given &[OsStr] slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut os_string = OsString::from("foo"); + /// os_string.push("bar"); + /// assert_eq!(&os_string, "foobar"); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[inline] + #[rustc_confusables("append", "put")] + pub fn push>(&mut self, s: T) { + trait SpecPushTo { + fn spec_push_to(&self, buf: &mut OsString); + } + + impl> SpecPushTo for T { + #[inline] + default fn spec_push_to(&self, buf: &mut OsString) { + buf.inner.push_slice(&self.as_ref().inner); + } + } + + // Use a more efficient implementation when the string is UTF-8. + macro spec_str($T:ty) { + impl SpecPushTo for $T { + #[inline] + fn spec_push_to(&self, buf: &mut OsString) { + buf.inner.push_str(self); + } + } + } + spec_str!(str); + spec_str!(String); + + s.spec_push_to(self) + } + + /// Creates a new `OsString` with at least the given capacity. + /// + /// The string will be able to hold at least `capacity` length units of other + /// OS strings without reallocating. This method is allowed to allocate for + /// more units than `capacity`. If `capacity` is 0, the string will not + /// allocate. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut os_string = OsString::with_capacity(10); + /// let capacity = os_string.capacity(); + /// + /// // This push is done without reallocating + /// os_string.push("foo"); + /// + /// assert_eq!(capacity, os_string.capacity()); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[must_use] + #[inline] + pub fn with_capacity(capacity: usize) -> OsString { + OsString { inner: Buf::with_capacity(capacity) } + } + + /// Truncates the `OsString` to zero length. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut os_string = OsString::from("foo"); + /// assert_eq!(&os_string, "foo"); + /// + /// os_string.clear(); + /// assert_eq!(&os_string, ""); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + /// Returns the capacity this `OsString` can hold without reallocating. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let os_string = OsString::with_capacity(10); + /// assert!(os_string.capacity() >= 10); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[must_use] + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + /// Reserves capacity for at least `additional` more capacity to be inserted + /// in the given `OsString`. Does nothing if the capacity is + /// already sufficient. + /// + /// The collection may reserve more space to speculatively avoid frequent reallocations. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::new(); + /// s.reserve(10); + /// assert!(s.capacity() >= 10); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + /// Tries to reserve capacity for at least `additional` more length units + /// in the given `OsString`. The string may reserve more space to speculatively avoid + /// frequent reallocations. After calling `try_reserve`, capacity will be + /// greater than or equal to `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if capacity is already sufficient. This method preserves + /// the contents even if an error occurs. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsStr, OsString}; + /// use std::collections::TryReserveError; + /// + /// fn process_data(data: &str) -> Result { + /// let mut s = OsString::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// s.try_reserve(OsStr::new(data).len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// s.push(data); + /// + /// Ok(s) + /// } + /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); + /// ``` + #[stable(feature = "try_reserve_2", since = "1.63.0")] + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve(additional) + } + + /// Reserves the minimum capacity for at least `additional` more capacity to + /// be inserted in the given `OsString`. Does nothing if the capacity is + /// already sufficient. + /// + /// Note that the allocator may give the collection more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`reserve`] if future insertions are expected. + /// + /// [`reserve`]: OsString::reserve + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::new(); + /// s.reserve_exact(10); + /// assert!(s.capacity() >= 10); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + + /// Tries to reserve the minimum capacity for at least `additional` + /// more length units in the given `OsString`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. + /// Does nothing if the capacity is already sufficient. + /// + /// Note that the allocator may give the `OsString` more space than it + /// requests. Therefore, capacity can not be relied upon to be precisely + /// minimal. Prefer [`try_reserve`] if future insertions are expected. + /// + /// [`try_reserve`]: OsString::try_reserve + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Errors + /// + /// If the capacity overflows, or the allocator reports a failure, then an error + /// is returned. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsStr, OsString}; + /// use std::collections::TryReserveError; + /// + /// fn process_data(data: &str) -> Result { + /// let mut s = OsString::new(); + /// + /// // Pre-reserve the memory, exiting if we can't + /// s.try_reserve_exact(OsStr::new(data).len())?; + /// + /// // Now we know this can't OOM in the middle of our complex work + /// s.push(data); + /// + /// Ok(s) + /// } + /// # process_data("123").expect("why is the test harness OOMing on 3 bytes?"); + /// ``` + #[stable(feature = "try_reserve_2", since = "1.63.0")] + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(additional) + } + + /// Shrinks the capacity of the `OsString` to match its length. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to_fit(); + /// assert_eq!(3, s.capacity()); + /// ``` + #[stable(feature = "osstring_shrink_to_fit", since = "1.19.0")] + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + + /// Shrinks the capacity of the `OsString` with a lower bound. + /// + /// The capacity will remain at least as large as both the length + /// and the supplied value. + /// + /// If the current capacity is less than the lower limit, this is a no-op. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("foo"); + /// + /// s.reserve(100); + /// assert!(s.capacity() >= 100); + /// + /// s.shrink_to(10); + /// assert!(s.capacity() >= 10); + /// s.shrink_to(0); + /// assert!(s.capacity() >= 3); + /// ``` + #[inline] + #[stable(feature = "shrink_to", since = "1.56.0")] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + + /// Converts this `OsString` into a boxed [`OsStr`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsString, OsStr}; + /// + /// let s = OsString::from("hello"); + /// + /// let b: Box = s.into_boxed_os_str(); + /// ``` + #[must_use = "`self` will be dropped if the result is not used"] + #[stable(feature = "into_boxed_os_str", since = "1.20.0")] + pub fn into_boxed_os_str(self) -> Box { + let rw = Box::into_raw(self.inner.into_box()) as *mut OsStr; + 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 + #[stable(feature = "os_string_pathbuf_leak", since = "1.89.0")] + #[inline] + pub fn leak<'a>(self) -> &'a mut OsStr { + OsStr::from_inner_mut(self.inner.leak()) + } + + /// Truncate the `OsString` to the specified length. + /// + /// # Panics + /// Panics if `len` does not lie on a valid `OsStr` boundary + /// (as described in [`OsStr::slice_encoded_bytes`]). + #[inline] + #[unstable(feature = "os_string_truncate", issue = "133262")] + pub fn truncate(&mut self, len: usize) { + self.as_os_str().inner.check_public_boundary(len); + // SAFETY: The length was just checked to be at a valid boundary. + unsafe { self.inner.truncate_unchecked(len) }; + } + + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// [`OsStr::from_encoded_bytes_unchecked`]). + /// + /// This bypasses the encoding-dependent surrogate joining, so either + /// `self` must not end with a leading surrogate half, or `other` must not + /// start with a trailing surrogate half. + #[inline] + pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { + // SAFETY: Guaranteed by caller. + unsafe { self.inner.extend_from_slice_unchecked(other) }; + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl From for OsString { + /// Converts a [`String`] into an [`OsString`]. + /// + /// This conversion does not allocate or copy memory. + #[inline] + fn from(s: String) -> OsString { + OsString { inner: Buf::from_string(s) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl> From<&T> for OsString { + /// Copies any value implementing [AsRef]<[OsStr]> + /// into a newly allocated [`OsString`]. + fn from(s: &T) -> OsString { + trait SpecToOsString { + fn spec_to_os_string(&self) -> OsString; + } + + impl> SpecToOsString for T { + #[inline] + default fn spec_to_os_string(&self) -> OsString { + self.as_ref().to_os_string() + } + } + + // Preserve the known-UTF-8 property for strings. + macro spec_str($T:ty) { + impl SpecToOsString for $T { + #[inline] + fn spec_to_os_string(&self) -> OsString { + OsString::from(String::from(self)) + } + } + } + spec_str!(str); + spec_str!(String); + + s.spec_to_os_string() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for OsString { + type Output = OsStr; + + #[inline] + fn index(&self, _index: ops::RangeFull) -> &OsStr { + OsStr::from_inner(self.inner.as_slice()) + } +} + +#[stable(feature = "mut_osstr", since = "1.44.0")] +impl ops::IndexMut for OsString { + #[inline] + fn index_mut(&mut self, _index: ops::RangeFull) -> &mut OsStr { + OsStr::from_inner_mut(self.inner.as_mut_slice()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Deref for OsString { + type Target = OsStr; + + #[inline] + fn deref(&self) -> &OsStr { + &self[..] + } +} + +#[stable(feature = "mut_osstr", since = "1.44.0")] +impl ops::DerefMut for OsString { + #[inline] + fn deref_mut(&mut self) -> &mut OsStr { + &mut self[..] + } +} + +#[stable(feature = "osstring_default", since = "1.9.0")] +impl Default for OsString { + /// Constructs an empty `OsString`. + #[inline] + fn default() -> OsString { + OsString::new() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for OsString { + #[inline] + fn clone(&self) -> Self { + OsString { inner: self.inner.clone() } + } + + /// Clones the contents of `source` into `self`. + /// + /// This method is preferred over simply assigning `source.clone()` to `self`, + /// as it avoids reallocation if possible. + #[inline] + fn clone_from(&mut self, source: &Self) { + self.inner.clone_from(&source.inner) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for OsString { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&**self, formatter) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for OsString { + #[inline] + fn eq(&self, other: &OsString) -> bool { + &**self == &**other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for OsString { + #[inline] + fn eq(&self, other: &str) -> bool { + &**self == other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for str { + #[inline] + fn eq(&self, other: &OsString) -> bool { + &**other == self + } +} + +#[stable(feature = "os_str_str_ref_eq", since = "1.29.0")] +impl PartialEq<&str> for OsString { + #[inline] + fn eq(&self, other: &&str) -> bool { + **self == **other + } +} + +#[stable(feature = "os_str_str_ref_eq", since = "1.29.0")] +impl<'a> PartialEq for &'a str { + #[inline] + fn eq(&self, other: &OsString) -> bool { + **other == **self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for OsString {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for OsString { + #[inline] + fn partial_cmp(&self, other: &OsString) -> Option { + (&**self).partial_cmp(&**other) + } + #[inline] + fn lt(&self, other: &OsString) -> bool { + &**self < &**other + } + #[inline] + fn le(&self, other: &OsString) -> bool { + &**self <= &**other + } + #[inline] + fn gt(&self, other: &OsString) -> bool { + &**self > &**other + } + #[inline] + fn ge(&self, other: &OsString) -> bool { + &**self >= &**other + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for OsString { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + (&**self).partial_cmp(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for OsString { + #[inline] + fn cmp(&self, other: &OsString) -> cmp::Ordering { + (&**self).cmp(&**other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for OsString { + #[inline] + fn hash(&self, state: &mut H) { + (&**self).hash(state) + } +} + +#[stable(feature = "os_string_fmt_write", since = "1.64.0")] +impl fmt::Write for OsString { + fn write_str(&mut self, s: &str) -> fmt::Result { + self.push(s); + Ok(()) + } +} + +impl OsStr { + /// Coerces into an `OsStr` slice. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// ``` + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + pub const fn new + ?Sized>(s: &S) -> &OsStr { + s.as_ref() + } + + /// Converts a slice of bytes to an OS string slice without checking that the string contains + /// valid `OsStr`-encoded data. + /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// + /// See the [module's toplevel documentation about conversions][conversions] for safe, + /// cross-platform [conversions] from/to native representations. + /// + /// # Safety + /// + /// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of + /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same Rust version + /// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent + /// over the network or stored in a file will likely violate these safety rules. + /// + /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be + /// split either immediately before or immediately after any valid non-empty UTF-8 substring. + /// + /// # Example + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("Mary had a little lamb"); + /// let bytes = os_str.as_encoded_bytes(); + /// let words = bytes.split(|b| *b == b' '); + /// let words: Vec<&OsStr> = words.map(|word| { + /// // SAFETY: + /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes` + /// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring + /// unsafe { OsStr::from_encoded_bytes_unchecked(word) } + /// }).collect(); + /// ``` + /// + /// [conversions]: super#conversions + #[inline] + #[stable(feature = "os_str_bytes", since = "1.74.0")] + pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self { + Self::from_inner(unsafe { Slice::from_encoded_bytes_unchecked(bytes) }) + } + + #[inline] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner(inner: &Slice) -> &OsStr { + // SAFETY: OsStr is just a wrapper of Slice, + // therefore converting &Slice to &OsStr is safe. + unsafe { &*(inner as *const Slice as *const OsStr) } + } + + #[inline] + #[rustc_const_unstable(feature = "const_convert", issue = "143773")] + const fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { + // SAFETY: OsStr is just a wrapper of Slice, + // therefore converting &mut Slice to &mut OsStr is safe. + // Any method that mutates OsStr must be careful not to + // break platform-specific encoding, in particular Wtf8 on Windows. + unsafe { &mut *(inner as *mut Slice as *mut OsStr) } + } + + /// Yields a &[str] slice if the `OsStr` is valid Unicode. + /// + /// This conversion may entail doing a check for UTF-8 validity. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_str.to_str(), Some("foo")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn to_str(&self) -> Option<&str> { + self.inner.to_str().ok() + } + + /// Converts an `OsStr` to a [Cow]<[str]>. + /// + /// Any non-UTF-8 sequences are replaced with + /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]. + /// + /// [U+FFFD]: crate::char::REPLACEMENT_CHARACTER + /// + /// # Examples + /// + /// Calling `to_string_lossy` on an `OsStr` with invalid unicode: + /// + /// ``` + /// // Note, due to differences in how Unix and Windows represent strings, + /// // we are forced to complicate this example, setting up example `OsStr`s + /// // with different source data and via different platform extensions. + /// // Understand that in reality you could end up with such example invalid + /// // sequences simply through collecting user command line arguments, for + /// // example. + /// + /// #[cfg(unix)] { + /// use std::ffi::OsStr; + /// use std::os::unix::ffi::OsStrExt; + /// + /// // Here, the values 0x66 and 0x6f correspond to 'f' and 'o' + /// // respectively. The value 0x80 is a lone continuation byte, invalid + /// // in a UTF-8 sequence. + /// let source = [0x66, 0x6f, 0x80, 0x6f]; + /// let os_str = OsStr::from_bytes(&source[..]); + /// + /// assert_eq!(os_str.to_string_lossy(), "fo�o"); + /// } + /// #[cfg(windows)] { + /// use std::ffi::OsString; + /// use std::os::windows::prelude::*; + /// + /// // Here the values 0x0066 and 0x006f correspond to 'f' and 'o' + /// // respectively. The value 0xD800 is a lone surrogate half, invalid + /// // in a UTF-16 sequence. + /// let source = [0x0066, 0x006f, 0xD800, 0x006f]; + /// let os_string = OsString::from_wide(&source[..]); + /// let os_str = os_string.as_os_str(); + /// + /// assert_eq!(os_str.to_string_lossy(), "fo�o"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub fn to_string_lossy(&self) -> Cow<'_, str> { + self.inner.to_string_lossy() + } + + /// Copies the slice into an owned [`OsString`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::{OsStr, OsString}; + /// + /// let os_str = OsStr::new("foo"); + /// let os_string = os_str.to_os_string(); + /// assert_eq!(os_string, OsString::from("foo")); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[cfg_attr(not(test), rustc_diagnostic_item = "os_str_to_os_string")] + pub fn to_os_string(&self) -> OsString { + OsString { inner: self.inner.to_owned() } + } + + /// Checks whether the `OsStr` is empty. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new(""); + /// assert!(os_str.is_empty()); + /// + /// let os_str = OsStr::new("foo"); + /// assert!(!os_str.is_empty()); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[must_use] + #[inline] + pub fn is_empty(&self) -> bool { + self.inner.inner.is_empty() + } + + /// Returns the length of this `OsStr`. + /// + /// Note that this does **not** return the number of bytes in the string in + /// OS string form. + /// + /// The length returned is that of the underlying storage used by `OsStr`. + /// As discussed in the [`OsString`] introduction, [`OsString`] and `OsStr` + /// store strings in a form best suited for cheap inter-conversion between + /// native-platform and Rust string forms, which may differ significantly + /// from both of them, including in storage size and encoding. + /// + /// This number is simply useful for passing to other methods, like + /// [`OsString::with_capacity`] to avoid reallocations. + /// + /// See the main `OsString` documentation information about encoding and capacity units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new(""); + /// assert_eq!(os_str.len(), 0); + /// + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_str.len(), 3); + /// ``` + #[stable(feature = "osstring_simple_functions", since = "1.9.0")] + #[must_use] + #[inline] + pub fn len(&self) -> usize { + self.inner.inner.len() + } + + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or allocating. + #[stable(feature = "into_boxed_os_str", since = "1.20.0")] + #[must_use = "`self` will be dropped if the result is not used"] + pub fn into_os_string(self: Box) -> OsString { + let boxed = unsafe { Box::from_raw(Box::into_raw(self) as *mut Slice) }; + OsString { inner: Buf::from_box(boxed) } + } + + /// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS + /// string slice, use the [`OsStr::from_encoded_bytes_unchecked`] function. + /// + /// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8. + /// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit + /// ASCII. + /// + /// Note: As the encoding is unspecified, any sub-slice of bytes that is not valid UTF-8 should + /// be treated as opaque and only comparable within the same Rust version built for the same + /// target platform. For example, sending the slice over the network or storing it in a file + /// will likely result in incompatible byte slices. See [`OsString`] for more encoding details + /// and [`std::ffi`] for platform-specific, specified conversions. + /// + /// [`std::ffi`]: crate::ffi + #[inline] + #[stable(feature = "os_str_bytes", since = "1.74.0")] + pub fn as_encoded_bytes(&self) -> &[u8] { + self.inner.as_encoded_bytes() + } + + /// Takes a substring based on a range that corresponds to the return value of + /// [`OsStr::as_encoded_bytes`]. + /// + /// The range's start and end must lie on valid `OsStr` boundaries. + /// A valid `OsStr` boundary is one of: + /// - The start of the string + /// - The end of the string + /// - Immediately before a valid non-empty UTF-8 substring + /// - Immediately after a valid non-empty UTF-8 substring + /// + /// # Panics + /// + /// Panics if `range` does not lie on valid `OsStr` boundaries or if it + /// exceeds the end of the string. + /// + /// # Example + /// + /// ``` + /// #![feature(os_str_slice)] + /// + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo=bar"); + /// let bytes = os_str.as_encoded_bytes(); + /// if let Some(index) = bytes.iter().position(|b| *b == b'=') { + /// let key = os_str.slice_encoded_bytes(..index); + /// let value = os_str.slice_encoded_bytes(index + 1..); + /// assert_eq!(key, "foo"); + /// assert_eq!(value, "bar"); + /// } + /// ``` + #[unstable(feature = "os_str_slice", issue = "118485")] + pub fn slice_encoded_bytes>(&self, range: R) -> &Self { + let encoded_bytes = self.as_encoded_bytes(); + let Range { start, end } = slice::range(range, ..encoded_bytes.len()); + + // `check_public_boundary` should panic if the index does not lie on an + // `OsStr` boundary as described above. It's possible to do this in an + // encoding-agnostic way, but details of the internal encoding might + // permit a more efficient implementation. + self.inner.check_public_boundary(start); + self.inner.check_public_boundary(end); + + // SAFETY: `slice::range` ensures that `start` and `end` are valid + let slice = unsafe { encoded_bytes.get_unchecked(start..end) }; + + // SAFETY: `slice` comes from `self` and we validated the boundaries + unsafe { Self::from_encoded_bytes_unchecked(slice) } + } + + /// Converts this string to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`OsStr::to_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("GRÜßE, JÜRGEN ❤"); + /// + /// s.make_ascii_lowercase(); + /// + /// assert_eq!("grÜße, jÜrgen ❤", s); + /// ``` + #[stable(feature = "osstring_ascii", since = "1.53.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + self.inner.make_ascii_lowercase() + } + + /// Converts this string to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`OsStr::to_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let mut s = OsString::from("Grüße, Jürgen ❤"); + /// + /// s.make_ascii_uppercase(); + /// + /// assert_eq!("GRüßE, JüRGEN ❤", s); + /// ``` + #[stable(feature = "osstring_ascii", since = "1.53.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + self.inner.make_ascii_uppercase() + } + + /// Returns a copy of this string where each character is mapped to its + /// ASCII lower case equivalent. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To lowercase the value in-place, use [`OsStr::make_ascii_lowercase`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// let s = OsString::from("Grüße, Jürgen ❤"); + /// + /// assert_eq!("grüße, jürgen ❤", s.to_ascii_lowercase()); + /// ``` + #[must_use = "to lowercase the value in-place, use `make_ascii_lowercase`"] + #[stable(feature = "osstring_ascii", since = "1.53.0")] + pub fn to_ascii_lowercase(&self) -> OsString { + OsString::from_inner(self.inner.to_ascii_lowercase()) + } + + /// Returns a copy of this string where each character is mapped to its + /// ASCII upper case equivalent. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To uppercase the value in-place, use [`OsStr::make_ascii_uppercase`]. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// let s = OsString::from("Grüße, Jürgen ❤"); + /// + /// assert_eq!("GRüßE, JüRGEN ❤", s.to_ascii_uppercase()); + /// ``` + #[must_use = "to uppercase the value in-place, use `make_ascii_uppercase`"] + #[stable(feature = "osstring_ascii", since = "1.53.0")] + pub fn to_ascii_uppercase(&self) -> OsString { + OsString::from_inner(self.inner.to_ascii_uppercase()) + } + + /// Checks if all characters in this string are within the ASCII range. + /// + /// An empty string returns `true`. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// let ascii = OsString::from("hello!\n"); + /// let non_ascii = OsString::from("Grüße, Jürgen ❤"); + /// + /// assert!(ascii.is_ascii()); + /// assert!(!non_ascii.is_ascii()); + /// ``` + #[stable(feature = "osstring_ascii", since = "1.53.0")] + #[must_use] + #[inline] + pub fn is_ascii(&self) -> bool { + self.inner.is_ascii() + } + + /// Checks that two strings are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// + /// assert!(OsString::from("Ferris").eq_ignore_ascii_case("FERRIS")); + /// assert!(OsString::from("Ferrös").eq_ignore_ascii_case("FERRöS")); + /// assert!(!OsString::from("Ferrös").eq_ignore_ascii_case("FERRÖS")); + /// ``` + #[stable(feature = "osstring_ascii", since = "1.53.0")] + pub fn eq_ignore_ascii_case>(&self, other: S) -> bool { + self.inner.eq_ignore_ascii_case(&other.as_ref().inner) + } + + /// Returns an object that implements [`Display`] for safely printing an + /// [`OsStr`] that may contain non-Unicode data. This may perform lossy + /// conversion, depending on the platform. If you would like an + /// implementation which escapes the [`OsStr`] please use [`Debug`] + /// instead. + /// + /// [`Display`]: fmt::Display + /// [`Debug`]: fmt::Debug + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let s = OsStr::new("Hello, world!"); + /// println!("{}", s.display()); + /// ``` + #[stable(feature = "os_str_display", since = "1.87.0")] + #[must_use = "this does not display the `OsStr`; \ + it returns an object that can be displayed"] + #[inline] + pub fn display(&self) -> Display<'_> { + Display { os_str: self } + } + + /// Returns the same string as a string slice `&OsStr`. + /// + /// This method is redundant when used directly on `&OsStr`, but + /// it helps dereferencing other string-like types to string slices, + /// for example references to `Box` or `Arc`. + #[inline] + #[unstable(feature = "str_as_str", issue = "130366")] + pub const fn as_os_str(&self) -> &OsStr { + self + } +} + +#[stable(feature = "box_from_os_str", since = "1.17.0")] +impl From<&OsStr> for Box { + /// Copies the string into a newly allocated [Box]<[OsStr]>. + #[inline] + fn from(s: &OsStr) -> Box { + Box::clone_from_ref(s) + } +} + +#[stable(feature = "box_from_mut_slice", since = "1.84.0")] +impl From<&mut OsStr> for Box { + /// Copies the string into a newly allocated [Box]<[OsStr]>. + #[inline] + fn from(s: &mut OsStr) -> Box { + Self::from(&*s) + } +} + +#[stable(feature = "box_from_cow", since = "1.45.0")] +impl From> for Box { + /// Converts a `Cow<'a, OsStr>` into a [Box]<[OsStr]>, + /// by copying the contents if they are borrowed. + #[inline] + fn from(cow: Cow<'_, OsStr>) -> Box { + match cow { + Cow::Borrowed(s) => Box::from(s), + Cow::Owned(s) => Box::from(s), + } + } +} + +#[stable(feature = "os_string_from_box", since = "1.18.0")] +impl From> for OsString { + /// Converts a [Box]<[OsStr]> into an [`OsString`] without copying or + /// allocating. + #[inline] + fn from(boxed: Box) -> OsString { + boxed.into_os_string() + } +} + +#[stable(feature = "box_from_os_string", since = "1.20.0")] +impl From for Box { + /// Converts an [`OsString`] into a [Box]<[OsStr]> without copying or allocating. + #[inline] + fn from(s: OsString) -> Box { + s.into_boxed_os_str() + } +} + +#[stable(feature = "more_box_slice_clone", since = "1.29.0")] +impl Clone for Box { + #[inline] + fn clone(&self) -> Self { + self.to_os_string().into_boxed_os_str() + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for OsStr { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around a platform-specific Slice + unsafe { self.inner.clone_to_uninit(dst) } + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl From for Arc { + /// Converts an [`OsString`] into an [Arc]<[OsStr]> by moving the [`OsString`] + /// data into a new [`Arc`] buffer. + #[inline] + fn from(s: OsString) -> Arc { + let arc = s.inner.into_arc(); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl From<&OsStr> for Arc { + /// Copies the string into a newly allocated [Arc]<[OsStr]>. + #[inline] + fn from(s: &OsStr) -> Arc { + let arc = s.inner.into_arc(); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const OsStr) } + } +} + +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] +impl From<&mut OsStr> for Arc { + /// Copies the string into a newly allocated [Arc]<[OsStr]>. + #[inline] + fn from(s: &mut OsStr) -> Arc { + Arc::from(&*s) + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl From for Rc { + /// Converts an [`OsString`] into an [Rc]<[OsStr]> by moving the [`OsString`] + /// data into a new [`Rc`] buffer. + #[inline] + fn from(s: OsString) -> Rc { + let rc = s.inner.into_rc(); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } + } +} + +#[stable(feature = "shared_from_slice2", since = "1.24.0")] +impl From<&OsStr> for Rc { + /// Copies the string into a newly allocated [Rc]<[OsStr]>. + #[inline] + fn from(s: &OsStr) -> Rc { + let rc = s.inner.into_rc(); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const OsStr) } + } +} + +#[stable(feature = "shared_from_mut_slice", since = "1.84.0")] +impl From<&mut OsStr> for Rc { + /// Copies the string into a newly allocated [Rc]<[OsStr]>. + #[inline] + fn from(s: &mut OsStr) -> Rc { + Rc::from(&*s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From for Cow<'a, OsStr> { + /// Moves the string into a [`Cow::Owned`]. + #[inline] + fn from(s: OsString) -> Cow<'a, OsStr> { + Cow::Owned(s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<&'a OsStr> for Cow<'a, OsStr> { + /// Converts the string reference into a [`Cow::Borrowed`]. + #[inline] + fn from(s: &'a OsStr) -> Cow<'a, OsStr> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_osstr", since = "1.28.0")] +impl<'a> From<&'a OsString> for Cow<'a, OsStr> { + /// Converts the string reference into a [`Cow::Borrowed`]. + #[inline] + fn from(s: &'a OsString) -> Cow<'a, OsStr> { + Cow::Borrowed(s.as_os_str()) + } +} + +#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")] +impl<'a> From> for OsString { + /// Converts a `Cow<'a, OsStr>` into an [`OsString`], + /// by copying the contents if they are borrowed. + #[inline] + fn from(s: Cow<'a, OsStr>) -> Self { + s.into_owned() + } +} + +#[stable(feature = "str_tryfrom_osstr_impl", since = "1.72.0")] +impl<'a> TryFrom<&'a OsStr> for &'a str { + type Error = crate::str::Utf8Error; + + /// Tries to convert an `&OsStr` to a `&str`. + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// let as_str = <&str>::try_from(os_str).unwrap(); + /// assert_eq!(as_str, "foo"); + /// ``` + fn try_from(value: &'a OsStr) -> Result { + value.inner.to_str() + } +} + +#[stable(feature = "box_default_extra", since = "1.17.0")] +impl Default for Box { + #[inline] + fn default() -> Box { + let rw = Box::into_raw(Slice::empty_box()) as *mut OsStr; + unsafe { Box::from_raw(rw) } + } +} + +#[stable(feature = "osstring_default", since = "1.9.0")] +impl Default for &OsStr { + /// Creates an empty `OsStr`. + #[inline] + fn default() -> Self { + OsStr::new("") + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for OsStr { + #[inline] + fn eq(&self, other: &OsStr) -> bool { + self.as_encoded_bytes().eq(other.as_encoded_bytes()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for OsStr { + #[inline] + fn eq(&self, other: &str) -> bool { + *self == *OsStr::new(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for str { + #[inline] + fn eq(&self, other: &OsStr) -> bool { + *other == *OsStr::new(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for OsStr {} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for OsStr { + #[inline] + fn partial_cmp(&self, other: &OsStr) -> Option { + self.as_encoded_bytes().partial_cmp(other.as_encoded_bytes()) + } + #[inline] + fn lt(&self, other: &OsStr) -> bool { + self.as_encoded_bytes().lt(other.as_encoded_bytes()) + } + #[inline] + fn le(&self, other: &OsStr) -> bool { + self.as_encoded_bytes().le(other.as_encoded_bytes()) + } + #[inline] + fn gt(&self, other: &OsStr) -> bool { + self.as_encoded_bytes().gt(other.as_encoded_bytes()) + } + #[inline] + fn ge(&self, other: &OsStr) -> bool { + self.as_encoded_bytes().ge(other.as_encoded_bytes()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for OsStr { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + self.partial_cmp(OsStr::new(other)) + } +} + +// FIXME (#19470): cannot provide PartialOrd for str until we +// have more flexible coherence rules. + +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for OsStr { + #[inline] + fn cmp(&self, other: &OsStr) -> cmp::Ordering { + self.as_encoded_bytes().cmp(other.as_encoded_bytes()) + } +} + +macro_rules! impl_cmp { + ($lhs:ty, $rhs: ty) => { + #[stable(feature = "cmp_os_str", since = "1.8.0")] + impl PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { + ::eq(self, other) + } + } + + #[stable(feature = "cmp_os_str", since = "1.8.0")] + impl PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { + ::eq(self, other) + } + } + + #[stable(feature = "cmp_os_str", since = "1.8.0")] + impl PartialOrd<$rhs> for $lhs { + #[inline] + fn partial_cmp(&self, other: &$rhs) -> Option { + ::partial_cmp(self, other) + } + } + + #[stable(feature = "cmp_os_str", since = "1.8.0")] + impl PartialOrd<$lhs> for $rhs { + #[inline] + fn partial_cmp(&self, other: &$lhs) -> Option { + ::partial_cmp(self, other) + } + } + }; +} + +impl_cmp!(OsString, OsStr); +impl_cmp!(OsString, &OsStr); +impl_cmp!(Cow<'_, OsStr>, OsStr); +impl_cmp!(Cow<'_, OsStr>, &OsStr); +impl_cmp!(Cow<'_, OsStr>, OsString); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Hash for OsStr { + #[inline] + fn hash(&self, state: &mut H) { + self.as_encoded_bytes().hash(state) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for OsStr { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner, formatter) + } +} + +/// Helper struct for safely printing an [`OsStr`] with [`format!`] and `{}`. +/// +/// An [`OsStr`] might contain non-Unicode data. This `struct` implements the +/// [`Display`] trait in a way that mitigates that. It is created by the +/// [`display`](OsStr::display) method on [`OsStr`]. This may perform lossy +/// conversion, depending on the platform. If you would like an implementation +/// which escapes the [`OsStr`] please use [`Debug`] instead. +/// +/// # Examples +/// +/// ``` +/// use std::ffi::OsStr; +/// +/// let s = OsStr::new("Hello, world!"); +/// println!("{}", s.display()); +/// ``` +/// +/// [`Display`]: fmt::Display +/// [`format!`]: crate::format +#[stable(feature = "os_str_display", since = "1.87.0")] +pub struct Display<'a> { + os_str: &'a OsStr, +} + +#[stable(feature = "os_str_display", since = "1.87.0")] +impl fmt::Debug for Display<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.os_str, f) + } +} + +#[stable(feature = "os_str_display", since = "1.87.0")] +impl fmt::Display for Display<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.os_str.inner, f) + } +} + +#[unstable(feature = "slice_concat_ext", issue = "27747")] +impl> alloc::slice::Join<&OsStr> for [S] { + type Output = OsString; + + fn join(slice: &Self, sep: &OsStr) -> OsString { + let Some((first, suffix)) = slice.split_first() else { + return OsString::new(); + }; + let first_owned = first.borrow().to_owned(); + suffix.iter().fold(first_owned, |mut a, b| { + a.push(sep); + a.push(b.borrow()); + a + }) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Borrow for OsString { + #[inline] + fn borrow(&self) -> &OsStr { + &self[..] + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ToOwned for OsStr { + type Owned = OsString; + #[inline] + fn to_owned(&self) -> OsString { + self.to_os_string() + } + #[inline] + fn clone_into(&self, target: &mut OsString) { + self.inner.clone_into(&mut target.inner) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_convert", issue = "143773")] +impl const AsRef for OsStr { + #[inline] + fn as_ref(&self) -> &OsStr { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for OsString { + #[inline] + fn as_ref(&self) -> &OsStr { + self + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for str { + #[inline] + fn as_ref(&self) -> &OsStr { + OsStr::from_inner(Slice::from_str(self)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl AsRef for String { + #[inline] + fn as_ref(&self) -> &OsStr { + (&**self).as_ref() + } +} + +impl FromInner for OsString { + #[inline] + fn from_inner(buf: Buf) -> OsString { + OsString { inner: buf } + } +} + +impl IntoInner for OsString { + #[inline] + fn into_inner(self) -> Buf { + self.inner + } +} + +impl AsInner for OsStr { + #[inline] + fn as_inner(&self) -> &Slice { + &self.inner + } +} + +#[stable(feature = "osstring_from_str", since = "1.45.0")] +impl FromStr for OsString { + type Err = core::convert::Infallible; + + #[inline] + fn from_str(s: &str) -> Result { + Ok(OsString::from(s)) + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl Extend for OsString { + #[inline] + fn extend>(&mut self, iter: T) { + for s in iter { + self.push(&s); + } + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> Extend<&'a OsStr> for OsString { + #[inline] + fn extend>(&mut self, iter: T) { + for s in iter { + self.push(s); + } + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> Extend> for OsString { + #[inline] + fn extend>>(&mut self, iter: T) { + for s in iter { + self.push(&s); + } + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl FromIterator for OsString { + #[inline] + fn from_iter>(iter: I) -> Self { + let mut iterator = iter.into_iter(); + + // Because we're iterating over `OsString`s, we can avoid at least + // one allocation by getting the first string from the iterator + // and appending to it all the subsequent strings. + match iterator.next() { + None => OsString::new(), + Some(mut buf) => { + buf.extend(iterator); + buf + } + } + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> FromIterator<&'a OsStr> for OsString { + #[inline] + fn from_iter>(iter: I) -> Self { + let mut buf = Self::new(); + for s in iter { + buf.push(s); + } + buf + } +} + +#[stable(feature = "osstring_extend", since = "1.52.0")] +impl<'a> FromIterator> for OsString { + #[inline] + fn from_iter>>(iter: I) -> Self { + let mut iterator = iter.into_iter(); + + // Because we're iterating over `OsString`s, we can avoid at least + // one allocation by getting the first owned string from the iterator + // and appending to it all the subsequent strings. + match iterator.next() { + None => OsString::new(), + Some(Cow::Owned(mut buf)) => { + buf.extend(iterator); + buf + } + Some(Cow::Borrowed(buf)) => { + let mut buf = OsString::from(buf); + buf.extend(iterator); + buf + } + } + } +} diff --git a/crates/std/src/ffi/os_str/tests.rs b/crates/std/src/ffi/os_str/tests.rs new file mode 100644 index 0000000..3474f0a --- /dev/null +++ b/crates/std/src/ffi/os_str/tests.rs @@ -0,0 +1,311 @@ +use super::*; +use crate::mem::MaybeUninit; +use crate::ptr; + +#[test] +fn test_os_string_with_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.inner.into_inner().capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.inner.into_inner().capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.inner.into_inner().capacity() >= 3); +} + +#[test] +fn test_os_string_clear() { + let mut os_string = OsString::from("abc"); + assert_eq!(3, os_string.inner.as_inner().len()); + + os_string.clear(); + assert_eq!(&os_string, ""); + assert_eq!(0, os_string.inner.as_inner().len()); +} + +#[test] +fn test_os_string_leak() { + let os_string = OsString::from("have a cake"); + let (len, cap) = (os_string.len(), os_string.capacity()); + let leaked = os_string.leak(); + assert_eq!(leaked.as_encoded_bytes(), b"have a cake"); + unsafe { drop(String::from_raw_parts(leaked as *mut OsStr as _, len, cap)) } +} + +#[test] +fn test_os_string_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.capacity() >= 3); +} + +#[test] +fn test_os_string_reserve() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve(16); + assert!(os_string.capacity() >= 33) +} + +#[test] +fn test_os_string_reserve_exact() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve_exact(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 33) +} + +#[test] +fn test_os_string_join() { + let strings = [OsStr::new("hello"), OsStr::new("dear"), OsStr::new("world")]; + assert_eq!("hello", strings[..1].join(OsStr::new(" "))); + assert_eq!("hello dear world", strings.join(OsStr::new(" "))); + assert_eq!("hellodearworld", strings.join(OsStr::new(""))); + assert_eq!("hello.\n dear.\n world", strings.join(OsStr::new(".\n "))); + + assert_eq!("dear world", strings[1..].join(&OsString::from(" "))); + + let strings_abc = [OsString::from("a"), OsString::from("b"), OsString::from("c")]; + assert_eq!("a b c", strings_abc.join(OsStr::new(" "))); +} + +#[test] +fn test_os_string_default() { + let os_string: OsString = Default::default(); + assert_eq!("", &os_string); +} + +#[test] +fn test_os_str_is_empty() { + let mut os_string = OsString::new(); + assert!(os_string.is_empty()); + + os_string.push("abc"); + assert!(!os_string.is_empty()); + + os_string.clear(); + assert!(os_string.is_empty()); +} + +#[test] +fn test_os_str_len() { + let mut os_string = OsString::new(); + assert_eq!(0, os_string.len()); + + os_string.push("abc"); + assert_eq!(3, os_string.len()); + + os_string.clear(); + assert_eq!(0, os_string.len()); +} + +#[test] +fn test_os_str_default() { + let os_str: &OsStr = Default::default(); + assert_eq!("", os_str); +} + +#[test] +fn into_boxed() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let boxed: Box = Box::from(os_str); + let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); + assert_eq!(os_str, &*boxed); + assert_eq!(&*boxed, &*os_string); + assert_eq!(&*os_string, os_str); +} + +#[test] +fn boxed_default() { + let boxed = >::default(); + assert!(boxed.is_empty()); +} + +#[test] +fn test_os_str_clone_into() { + let mut os_string = OsString::with_capacity(123); + os_string.push("hello"); + let os_str = OsStr::new("bonjour"); + os_str.clone_into(&mut os_string); + assert_eq!(os_str, os_string); + assert!(os_string.capacity() >= 123); +} + +#[test] +fn into_rc() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let rc: Rc = Rc::from(os_str); + let arc: Arc = Arc::from(os_str); + + assert_eq!(&*rc, os_str); + assert_eq!(&*arc, os_str); + + let rc2: Rc = Rc::from(os_str.to_owned()); + let arc2: Arc = Arc::from(os_str.to_owned()); + + assert_eq!(&*rc2, os_str); + assert_eq!(&*arc2, os_str); +} + +#[test] +fn slice_encoded_bytes() { + let os_str = OsStr::new("123θგ🦀"); + // ASCII + let digits = os_str.slice_encoded_bytes(..3); + assert_eq!(digits, "123"); + let three = os_str.slice_encoded_bytes(2..3); + assert_eq!(three, "3"); + // 2-byte UTF-8 + let theta = os_str.slice_encoded_bytes(3..5); + assert_eq!(theta, "θ"); + // 3-byte UTF-8 + let gani = os_str.slice_encoded_bytes(5..8); + assert_eq!(gani, "გ"); + // 4-byte UTF-8 + let crab = os_str.slice_encoded_bytes(8..); + assert_eq!(crab, "🦀"); +} + +#[test] +#[should_panic] +fn slice_out_of_bounds() { + let crab = OsStr::new("🦀"); + let _ = crab.slice_encoded_bytes(..5); +} + +#[test] +#[should_panic] +fn slice_mid_char() { + let crab = OsStr::new("🦀"); + let _ = crab.slice_encoded_bytes(..2); +} + +#[cfg(unix)] +#[test] +#[should_panic(expected = "byte index 1 is not an OsStr boundary")] +fn slice_invalid_data() { + use crate::os::unix::ffi::OsStrExt; + + let os_string = OsStr::from_bytes(b"\xFF\xFF"); + let _ = os_string.slice_encoded_bytes(1..); +} + +#[cfg(unix)] +#[test] +#[should_panic(expected = "byte index 1 is not an OsStr boundary")] +fn slice_partial_utf8() { + use crate::os::unix::ffi::{OsStrExt, OsStringExt}; + + let part_crab = OsStr::from_bytes(&"🦀".as_bytes()[..3]); + let mut os_string = OsString::from_vec(vec![0xFF]); + os_string.push(part_crab); + let _ = os_string.slice_encoded_bytes(1..); +} + +#[cfg(unix)] +#[test] +fn slice_invalid_edge() { + use crate::os::unix::ffi::{OsStrExt, OsStringExt}; + + let os_string = OsStr::from_bytes(b"a\xFFa"); + assert_eq!(os_string.slice_encoded_bytes(..1), "a"); + assert_eq!(os_string.slice_encoded_bytes(1..), OsStr::from_bytes(b"\xFFa")); + assert_eq!(os_string.slice_encoded_bytes(..2), OsStr::from_bytes(b"a\xFF")); + assert_eq!(os_string.slice_encoded_bytes(2..), "a"); + + let os_string = OsStr::from_bytes(&"abc🦀".as_bytes()[..6]); + assert_eq!(os_string.slice_encoded_bytes(..3), "abc"); + assert_eq!(os_string.slice_encoded_bytes(3..), OsStr::from_bytes(b"\xF0\x9F\xA6")); + + let mut os_string = OsString::from_vec(vec![0xFF]); + os_string.push("🦀"); + assert_eq!(os_string.slice_encoded_bytes(..1), OsStr::from_bytes(b"\xFF")); + assert_eq!(os_string.slice_encoded_bytes(1..), "🦀"); +} + +#[cfg(windows)] +#[test] +#[should_panic(expected = "byte index 3 lies between surrogate codepoints")] +fn slice_between_surrogates() { + use crate::os::windows::ffi::OsStringExt; + + let os_string = OsString::from_wide(&[0xD800, 0xD800]); + assert_eq!(os_string.as_encoded_bytes(), &[0xED, 0xA0, 0x80, 0xED, 0xA0, 0x80]); + let _ = os_string.slice_encoded_bytes(..3); +} + +#[cfg(windows)] +#[test] +fn slice_surrogate_edge() { + use crate::os::windows::ffi::OsStringExt; + + let surrogate = OsString::from_wide(&[0xD800]); + let mut pre_crab = surrogate.clone(); + pre_crab.push("🦀"); + assert_eq!(pre_crab.slice_encoded_bytes(..3), surrogate); + assert_eq!(pre_crab.slice_encoded_bytes(3..), "🦀"); + + let mut post_crab = OsString::from("🦀"); + post_crab.push(&surrogate); + assert_eq!(post_crab.slice_encoded_bytes(..4), "🦀"); + assert_eq!(post_crab.slice_encoded_bytes(4..), surrogate); +} + +#[test] +fn clone_to_uninit() { + let a = OsStr::new("hello.txt"); + + let mut storage = vec![MaybeUninit::::uninit(); size_of_val::(a)]; + unsafe { a.clone_to_uninit(ptr::from_mut::<[_]>(storage.as_mut_slice()).cast()) }; + assert_eq!(a.as_encoded_bytes(), unsafe { storage.assume_init_ref() }); + + let mut b: Box = OsStr::new("world.exe").into(); + assert_eq!(size_of_val::(a), size_of_val::(&b)); + assert_ne!(a, &*b); + unsafe { a.clone_to_uninit(ptr::from_mut::(&mut b).cast()) }; + assert_eq!(a, &*b); +} + +#[test] +fn debug() { + let s = "'single quotes'"; + assert_eq!(format!("{:?}", OsStr::new(s)), format!("{:?}", s)); +} diff --git a/crates/std/src/hash/mod.rs b/crates/std/src/hash/mod.rs new file mode 100644 index 0000000..e88f5cb --- /dev/null +++ b/crates/std/src/hash/mod.rs @@ -0,0 +1,91 @@ +//! Generic hashing support. +//! +//! This module provides a generic way to compute the [hash] of a value. +//! Hashes are most commonly used with [`HashMap`] and [`HashSet`]. +//! +//! [hash]: https://en.wikipedia.org/wiki/Hash_function +//! [`HashMap`]: ../../std/collections/struct.HashMap.html +//! [`HashSet`]: ../../std/collections/struct.HashSet.html +//! +//! The simplest way to make a type hashable is to use `#[derive(Hash)]`: +//! +//! # Examples +//! +//! ```rust +//! use std::hash::{DefaultHasher, Hash, Hasher}; +//! +//! #[derive(Hash)] +//! struct Person { +//! id: u32, +//! name: String, +//! phone: u64, +//! } +//! +//! let person1 = Person { +//! id: 5, +//! name: "Janet".to_string(), +//! phone: 555_666_7777, +//! }; +//! let person2 = Person { +//! id: 5, +//! name: "Bob".to_string(), +//! phone: 555_666_7777, +//! }; +//! +//! assert!(calculate_hash(&person1) != calculate_hash(&person2)); +//! +//! fn calculate_hash(t: &T) -> u64 { +//! let mut s = DefaultHasher::new(); +//! t.hash(&mut s); +//! s.finish() +//! } +//! ``` +//! +//! If you need more control over how a value is hashed, you need to implement +//! the [`Hash`] trait: +//! +//! ```rust +//! use std::hash::{DefaultHasher, Hash, Hasher}; +//! +//! struct Person { +//! id: u32, +//! # #[allow(dead_code)] +//! name: String, +//! phone: u64, +//! } +//! +//! impl Hash for Person { +//! fn hash(&self, state: &mut H) { +//! self.id.hash(state); +//! self.phone.hash(state); +//! } +//! } +//! +//! let person1 = Person { +//! id: 5, +//! name: "Janet".to_string(), +//! phone: 555_666_7777, +//! }; +//! let person2 = Person { +//! id: 5, +//! name: "Bob".to_string(), +//! phone: 555_666_7777, +//! }; +//! +//! assert_eq!(calculate_hash(&person1), calculate_hash(&person2)); +//! +//! fn calculate_hash(t: &T) -> u64 { +//! let mut s = DefaultHasher::new(); +//! t.hash(&mut s); +//! s.finish() +//! } +//! ``` +// #![stable(feature = "rust1", since = "1.0.0")] + +// pub(crate) mod random; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::hash::*; + +// #[stable(feature = "std_hash_exports", since = "1.76.0")] +// pub use self::random::{DefaultHasher, RandomState}; diff --git a/crates/std/src/io.rs b/crates/std/src/io.rs index 709f22d..74e35a2 100644 --- a/crates/std/src/io.rs +++ b/crates/std/src/io.rs @@ -12,7 +12,7 @@ impl IoBase for Stdin { } impl Read for Stdin { - fn read(&mut self, buf: &mut [u8]) -> Result { + fn read(&mut self, buf: &mut [u8]) -> core::result::Result { unsafe { File::from_raw_fd(0).read(buf) } } } @@ -20,3 +20,20 @@ impl Read for Stdin { pub fn stdin() -> Stdin { Stdin } + +pub type Result = core::result::Result; + +pub(super) struct Repr(); + +// Part took from the real std +#[rustc_macro_transparency = "semiopaque"] +#[unstable(feature = "io_const_error", issue = "133448")] +#[allow_internal_unstable(hint_must_use, io_const_error_internals)] +pub macro const_error($kind:expr, $message:expr $(,)?) { + () +} + +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Error { + repr: Repr, +} diff --git a/crates/std/src/lib.rs b/crates/std/src/lib.rs index 871b601..c3d17ee 100644 --- a/crates/std/src/lib.rs +++ b/crates/std/src/lib.rs @@ -1,5 +1,34 @@ +#![unstable(feature = "custom_std", issue = "none")] #![no_std] +// +// Lints: +#![warn(deprecated_in_future)] +// #![warn(missing_docs)] +// #![warn(missing_debug_implementations)] +#![allow(explicit_outlives_requirements)] +#![allow(unused_lifetimes)] #![allow(internal_features)] +#![deny(fuzzy_provenance_casts)] +#![deny(unsafe_op_in_unsafe_fn)] +#![allow(rustdoc::redundant_explicit_links)] +#![warn(rustdoc::unescaped_backticks)] +// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind` +#![deny(ffi_unwind_calls)] +// std may use features in a platform-specific way +#![allow(unused_features)] +// +// Features: +#![cfg_attr( + test, + feature(internal_output_capture, print_internals, update_panic_count, rt) +)] +#![cfg_attr( + all(target_vendor = "fortanix", target_env = "sgx"), + feature(slice_index_methods, coerce_unsized, sgx_platform) +)] +#![cfg_attr(all(test, target_os = "uefi"), feature(uefi_std))] +#![cfg_attr(target_family = "wasm", feature(stdarch_wasm_atomic_wait))] +#![cfg_attr(target_arch = "wasm64", feature(simd_wasm64))] // // Language features: // tidy-alphabetical-start @@ -44,7 +73,7 @@ #![feature(prelude_import)] #![feature(rustc_attrs)] #![feature(rustdoc_internals)] -// #![feature(staged_api)] +#![feature(staged_api)] #![feature(stmt_expr_attributes)] #![feature(strict_provenance_lints)] #![feature(thread_local)] @@ -149,12 +178,14 @@ // // Only for const-ness: // tidy-alphabetical-start -// #![feature(io_const_error)] +#![feature(io_const_error)] // tidy-alphabetical-end // + #![feature(c_size_t, unsafe_binders)] -#![allow(clippy::doc_lazy_continuation, clippy::legacy_numeric_constants)] +#![allow(clippy::doc_lazy_continuation, clippy::all)] #![allow(stable_features, incomplete_features)] +#![allow(unused)] extern crate alloc; @@ -216,9 +247,24 @@ pub use alloc::string; pub use alloc::vec; pub mod ffi; +pub mod hash; pub mod io; pub mod prelude; pub mod process; +pub mod sys; + +#[prelude_import] +#[allow(unused_imports)] +pub use prelude::rust_2024::*; + +#[allow(unused)] +mod sealed { + /// This trait being unreachable from outside the crate + /// prevents outside implementations of our extension traits. + /// This allows adding more trait methods in the future. + #[unstable(feature = "sealed", issue = "none")] + pub trait Sealed {} +} pub use shared::fs; pub use shared::syscall; diff --git a/crates/std/src/prelude.rs b/crates/std/src/prelude.rs index 895a601..98f8d01 100644 --- a/crates/std/src/prelude.rs +++ b/crates/std/src/prelude.rs @@ -1,11 +1,134 @@ pub mod rust_2024 { pub use crate::print; pub use crate::println; - pub use alloc::borrow::ToOwned; pub use alloc::format; - pub use alloc::string::String; pub use alloc::vec; + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use crate::borrow::ToOwned; + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use crate::boxed::Box; + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use crate::string::{String, ToString}; + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use crate::vec::Vec; + + // Re-exported built-in macros and traits + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] + #[doc(no_inline)] + #[expect(deprecated)] + pub use core::prelude::v1::{ + Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, assert, assert_eq, + assert_ne, cfg, column, compile_error, concat, debug_assert, debug_assert_eq, + debug_assert_ne, env, file, format_args, include, include_bytes, include_str, line, + matches, module_path, option_env, stringify, todo, r#try, unimplemented, unreachable, + write, writeln, + }; + + #[stable(feature = "cfg_select", since = "1.95.0")] + #[doc(no_inline)] + pub use core::prelude::v1::cfg_select; + + #[unstable( + feature = "concat_bytes", + issue = "87555", + reason = "`concat_bytes` is not stable enough for use and is subject to change" + )] + #[doc(no_inline)] + pub use core::prelude::v1::concat_bytes; + + #[unstable(feature = "const_format_args", issue = "none")] + #[doc(no_inline)] + pub use core::prelude::v1::const_format_args; + + #[unstable( + feature = "log_syntax", + issue = "29598", + reason = "`log_syntax!` is not stable enough for use and is subject to change" + )] + #[doc(no_inline)] + pub use core::prelude::v1::log_syntax; + + #[unstable( + feature = "trace_macros", + issue = "29598", + reason = "`trace_macros` is not stable enough for use and is subject to change" + )] + #[doc(no_inline)] + pub use core::prelude::v1::trace_macros; + + // Do not `doc(no_inline)` so that they become doc items on their own + // (no public module for them to be re-exported from). + #[stable(feature = "builtin_macro_prelude", since = "1.38.0")] + pub use core::prelude::v1::{ + alloc_error_handler, bench, derive, global_allocator, test, test_case, + }; + + #[unstable(feature = "derive_const", issue = "118304")] + pub use core::prelude::v1::derive_const; + + // Do not `doc(no_inline)` either. + #[unstable( + feature = "cfg_accessible", + issue = "64797", + reason = "`cfg_accessible` is not fully implemented" + )] + pub use core::prelude::v1::cfg_accessible; + + // Do not `doc(no_inline)` either. + #[unstable( + feature = "cfg_eval", + issue = "82679", + reason = "`cfg_eval` is a recently implemented feature" + )] + pub use core::prelude::v1::cfg_eval; + + // Do not `doc(no_inline)` either. + #[unstable( + feature = "type_ascription", + issue = "23416", + reason = "placeholder syntax for type ascription" + )] + pub use core::prelude::v1::type_ascribe; + + // Do not `doc(no_inline)` either. + #[unstable( + feature = "deref_patterns", + issue = "87121", + reason = "placeholder syntax for deref patterns" + )] + pub use core::prelude::v1::deref; + + // Do not `doc(no_inline)` either. + #[unstable( + feature = "type_alias_impl_trait", + issue = "63063", + reason = "`type_alias_impl_trait` has open design concerns" + )] + pub use core::prelude::v1::define_opaque; + + #[unstable(feature = "extern_item_impls", issue = "125418")] + pub use core::prelude::v1::{eii, unsafe_eii}; + + #[unstable(feature = "eii_internals", issue = "none")] + pub use core::prelude::v1::eii_declaration; + + #[stable(feature = "prelude_2021", since = "1.55.0")] + #[doc(no_inline)] + pub use core::prelude::rust_2021::*; + + #[stable(feature = "prelude_2024", since = "1.85.0")] + #[doc(no_inline)] + pub use core::prelude::rust_2024::*; + + #[stable(feature = "rust1", since = "1.0.0")] + #[doc(no_inline)] + pub use crate::convert::{AsMut, AsRef, From, Into}; + extern crate alloc; struct GlobalAllocator; diff --git a/crates/std/src/sys/env/mod.rs b/crates/std/src/sys/env/mod.rs new file mode 100644 index 0000000..8985651 --- /dev/null +++ b/crates/std/src/sys/env/mod.rs @@ -0,0 +1,62 @@ +//! Platform-dependent environment variables abstraction. + +#![forbid(unsafe_op_in_unsafe_fn)] + +#[cfg(any( + target_family = "unix", + target_os = "hermit", + target_os = "motor", + all(target_vendor = "fortanix", target_env = "sgx"), + target_os = "solid_asp3", + target_os = "uefi", + target_os = "wasi", + target_os = "xous", +))] +mod common; + +cfg_select! { + target_family = "unix" => { + mod unix; + pub use unix::*; + } + target_family = "windows" => { + mod windows; + pub use windows::*; + } + target_os = "hermit" => { + mod hermit; + pub use hermit::*; + } + target_os = "motor" => { + mod motor; + pub use motor::*; + } + all(target_vendor = "fortanix", target_env = "sgx") => { + mod sgx; + pub use sgx::*; + } + target_os = "solid_asp3" => { + mod solid; + pub use solid::*; + } + target_os = "uefi" => { + mod uefi; + pub use uefi::*; + } + target_os = "wasi" => { + mod wasi; + pub use wasi::*; + } + target_os = "xous" => { + mod xous; + pub use xous::*; + } + target_os = "zkvm" => { + mod zkvm; + pub use zkvm::*; + } + _ => { + mod unsupported; + pub use unsupported::*; + } +} diff --git a/crates/std/src/sys/env/unsupported.rs b/crates/std/src/sys/env/unsupported.rs new file mode 100644 index 0000000..a967ace --- /dev/null +++ b/crates/std/src/sys/env/unsupported.rs @@ -0,0 +1,33 @@ +use crate::ffi::{OsStr, OsString}; +use crate::{fmt, io}; + +pub struct Env(!); + +impl fmt::Debug for Env { + fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0 + } +} + +impl Iterator for Env { + type Item = (OsString, OsString); + fn next(&mut self) -> Option<(OsString, OsString)> { + self.0 + } +} + +pub fn env() -> Env { + panic!("not supported on this platform") +} + +pub fn getenv(_: &OsStr) -> Option { + None +} + +pub unsafe fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform")) +} + +pub unsafe fn unsetenv(_: &OsStr) -> io::Result<()> { + Err(io::const_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform")) +} diff --git a/crates/std/src/sys/mod.rs b/crates/std/src/sys/mod.rs new file mode 100644 index 0000000..0b12d30 --- /dev/null +++ b/crates/std/src/sys/mod.rs @@ -0,0 +1,24 @@ +pub mod env; +pub mod os_str; + +/// A trait for viewing representations from std types. +#[cfg_attr(not(target_os = "linux"), allow(unused))] +pub(crate) trait AsInner { + fn as_inner(&self) -> &Inner; +} + +/// A trait for viewing representations from std types. +#[cfg_attr(not(target_os = "linux"), allow(unused))] +pub(crate) trait AsInnerMut { + fn as_inner_mut(&mut self) -> &mut Inner; +} + +/// A trait for extracting representations from std types. +pub(crate) trait IntoInner { + fn into_inner(self) -> Inner; +} + +/// A trait for creating std types from internal representations. +pub(crate) trait FromInner { + fn from_inner(inner: Inner) -> Self; +} diff --git a/crates/std/src/sys/os_str/bytes.rs b/crates/std/src/sys/os_str/bytes.rs new file mode 100644 index 0000000..960d8c6 --- /dev/null +++ b/crates/std/src/sys/os_str/bytes.rs @@ -0,0 +1,363 @@ +//! The underlying OsString/OsStr implementation on Unix and many other +//! systems: just a `Vec`/`[u8]`. + +use core::clone::CloneToUninit; + +use crate::borrow::Cow; +use alloc::bstr::ByteStr; +use alloc::collections::TryReserveError; +use crate::rc::Rc; +use alloc::sync::Arc; +use crate::sys::{AsInner, FromInner, IntoInner}; +use crate::{fmt, mem, str}; + +#[cfg(test)] +mod tests; + +#[derive(Hash)] +#[repr(transparent)] +pub struct Buf { + pub inner: Vec, +} + +#[repr(transparent)] +pub struct Slice { + pub inner: [u8], +} + +impl IntoInner> for Buf { + fn into_inner(self) -> Vec { + self.inner + } +} + +impl FromInner> for Buf { + fn from_inner(inner: Vec) -> Self { + Buf { inner } + } +} + +impl AsInner<[u8]> for Buf { + #[inline] + fn as_inner(&self) -> &[u8] { + &self.inner + } +} + +impl fmt::Debug for Buf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(self.as_slice(), f) + } +} + +impl fmt::Display for Buf { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self.as_slice(), f) + } +} + +impl fmt::Debug for Slice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.inner.utf8_chunks().debug(), f) + } +} + +impl fmt::Display for Slice { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(ByteStr::new(&self.inner), f) + } +} + +impl Clone for Buf { + #[inline] + fn clone(&self) -> Self { + Buf { inner: self.inner.clone() } + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + self.inner.clone_from(&source.inner) + } +} + +impl Buf { + #[inline] + pub fn into_encoded_bytes(self) -> Vec { + self.inner + } + + #[inline] + pub unsafe fn from_encoded_bytes_unchecked(s: Vec) -> Self { + Self { inner: s } + } + + #[inline] + pub fn into_string(self) -> Result { + String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() }) + } + + #[inline] + pub const fn from_string(s: String) -> Buf { + Buf { inner: s.into_bytes() } + } + + #[inline] + pub fn with_capacity(capacity: usize) -> Buf { + Buf { inner: Vec::with_capacity(capacity) } + } + + #[inline] + pub fn clear(&mut self) { + self.inner.clear() + } + + #[inline] + pub fn capacity(&self) -> usize { + self.inner.capacity() + } + + #[inline] + pub fn push_slice(&mut self, s: &Slice) { + self.inner.extend_from_slice(&s.inner) + } + + #[inline] + pub fn push_str(&mut self, s: &str) { + self.inner.extend_from_slice(s.as_bytes()); + } + + #[inline] + pub fn reserve(&mut self, additional: usize) { + self.inner.reserve(additional) + } + + #[inline] + pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve(additional) + } + + #[inline] + pub fn reserve_exact(&mut self, additional: usize) { + self.inner.reserve_exact(additional) + } + + #[inline] + pub fn try_reserve_exact(&mut self, additional: usize) -> Result<(), TryReserveError> { + self.inner.try_reserve_exact(additional) + } + + #[inline] + pub fn shrink_to_fit(&mut self) { + self.inner.shrink_to_fit() + } + + #[inline] + pub fn shrink_to(&mut self, min_capacity: usize) { + self.inner.shrink_to(min_capacity) + } + + #[inline] + pub fn as_slice(&self) -> &Slice { + // SAFETY: Slice is just a wrapper for [u8], + // and self.inner.as_slice() returns &[u8]. + // Therefore, transmuting &[u8] to &Slice is safe. + unsafe { mem::transmute(self.inner.as_slice()) } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut Slice { + // SAFETY: Slice is just a wrapper for [u8], + // and self.inner.as_mut_slice() returns &mut [u8]. + // Therefore, transmuting &mut [u8] to &mut Slice is safe. + unsafe { mem::transmute(self.inner.as_mut_slice()) } + } + + #[inline] + pub fn leak<'a>(self) -> &'a mut Slice { + unsafe { mem::transmute(self.inner.leak()) } + } + + #[inline] + pub fn into_box(self) -> Box { + unsafe { mem::transmute(self.inner.into_boxed_slice()) } + } + + #[inline] + pub fn from_box(boxed: Box) -> Buf { + let inner: Box<[u8]> = unsafe { mem::transmute(boxed) }; + Buf { inner: inner.into_vec() } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + self.as_slice().into_arc() + } + + #[inline] + pub fn into_rc(&self) -> Rc { + self.as_slice().into_rc() + } + + /// Provides plumbing to `Vec::truncate` without giving full mutable access + /// to the `Vec`. + /// + /// # Safety + /// + /// The length must be at an `OsStr` boundary, according to + /// `Slice::check_public_boundary`. + #[inline] + pub unsafe fn truncate_unchecked(&mut self, len: usize) { + self.inner.truncate(len); + } + + /// Provides plumbing to `Vec::extend_from_slice` without giving full + /// mutable access to the `Vec`. + /// + /// # Safety + /// + /// The slice must be valid for the platform encoding (as described in + /// `OsStr::from_encoded_bytes_unchecked`). This encoding has no safety + /// requirements. + #[inline] + pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) { + self.inner.extend_from_slice(other); + } +} + +impl Slice { + #[inline] + pub fn as_encoded_bytes(&self) -> &[u8] { + &self.inner + } + + #[inline] + pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice { + unsafe { mem::transmute(s) } + } + + #[track_caller] + #[inline] + pub fn check_public_boundary(&self, index: usize) { + if index == 0 || index == self.inner.len() { + return; + } + if index < self.inner.len() + && (self.inner[index - 1].is_ascii() || self.inner[index].is_ascii()) + { + return; + } + + slow_path(&self.inner, index); + + /// We're betting that typical splits will involve an ASCII character. + /// + /// Putting the expensive checks in a separate function generates notably + /// better assembly. + #[track_caller] + #[inline(never)] + fn slow_path(bytes: &[u8], index: usize) { + let (before, after) = bytes.split_at(index); + + // UTF-8 takes at most 4 bytes per codepoint, so we don't + // need to check more than that. + let after = after.get(..4).unwrap_or(after); + match str::from_utf8(after) { + Ok(_) => return, + Err(err) if err.valid_up_to() != 0 => return, + Err(_) => (), + } + + for len in 2..=4.min(index) { + let before = &before[index - len..]; + if str::from_utf8(before).is_ok() { + return; + } + } + + panic!("byte index {index} is not an OsStr boundary"); + } + } + + #[inline] + pub fn from_str(s: &str) -> &Slice { + unsafe { Slice::from_encoded_bytes_unchecked(s.as_bytes()) } + } + + #[inline] + pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> { + str::from_utf8(&self.inner) + } + + #[inline] + pub fn to_string_lossy(&self) -> Cow<'_, str> { + String::from_utf8_lossy(&self.inner) + } + + #[inline] + pub fn to_owned(&self) -> Buf { + Buf { inner: self.inner.to_vec() } + } + + #[inline] + pub fn clone_into(&self, buf: &mut Buf) { + self.inner.clone_into(&mut buf.inner) + } + + #[inline] + pub fn empty_box() -> Box { + let boxed: Box<[u8]> = Default::default(); + unsafe { mem::transmute(boxed) } + } + + #[inline] + pub fn into_arc(&self) -> Arc { + let arc: Arc<[u8]> = Arc::from(&self.inner); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } + } + + #[inline] + pub fn into_rc(&self) -> Rc { + let rc: Rc<[u8]> = Rc::from(&self.inner); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } + } + + #[inline] + pub fn make_ascii_lowercase(&mut self) { + self.inner.make_ascii_lowercase() + } + + #[inline] + pub fn make_ascii_uppercase(&mut self) { + self.inner.make_ascii_uppercase() + } + + #[inline] + pub fn to_ascii_lowercase(&self) -> Buf { + Buf { inner: self.inner.to_ascii_lowercase() } + } + + #[inline] + pub fn to_ascii_uppercase(&self) -> Buf { + Buf { inner: self.inner.to_ascii_uppercase() } + } + + #[inline] + pub fn is_ascii(&self) -> bool { + self.inner.is_ascii() + } + + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { + self.inner.eq_ignore_ascii_case(&other.inner) + } +} + +#[unstable(feature = "clone_to_uninit", issue = "126799")] +unsafe impl CloneToUninit for Slice { + #[inline] + #[cfg_attr(debug_assertions, track_caller)] + unsafe fn clone_to_uninit(&self, dst: *mut u8) { + // SAFETY: we're just a transparent wrapper around [u8] + unsafe { self.inner.clone_to_uninit(dst) } + } +} diff --git a/crates/std/src/sys/os_str/bytes/tests.rs b/crates/std/src/sys/os_str/bytes/tests.rs new file mode 100644 index 0000000..e2a9904 --- /dev/null +++ b/crates/std/src/sys/os_str/bytes/tests.rs @@ -0,0 +1,17 @@ +use super::*; + +#[test] +fn slice_debug_output() { + let input = unsafe { Slice::from_encoded_bytes_unchecked(b"\xF0hello,\tworld") }; + let expected = r#""\xF0hello,\tworld""#; + let output = format!("{input:?}"); + + assert_eq!(output, expected); +} + +#[test] +fn display() { + assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe { + Slice::from_encoded_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string() + },); +} diff --git a/crates/std/src/sys/os_str/mod.rs b/crates/std/src/sys/os_str/mod.rs new file mode 100644 index 0000000..f7007cb --- /dev/null +++ b/crates/std/src/sys/os_str/mod.rs @@ -0,0 +1,16 @@ +#![forbid(unsafe_op_in_unsafe_fn)] + +cfg_select! { + any(target_os = "windows", target_os = "uefi") => { + mod wtf8; + pub use wtf8::{Buf, Slice}; + } + any(target_os = "motor") => { + mod utf8; + pub use utf8::{Buf, Slice}; + } + _ => { + mod bytes; + pub use bytes::{Buf, Slice}; + } +} diff --git a/justfile b/justfile index d8c779b..ba32dd5 100644 --- a/justfile +++ b/justfile @@ -17,13 +17,21 @@ cp_std path: @echo "Copying {{ path }}" @mkdir {{ "crates/std/src" / parent_directory(path) }} -p @cp {{ rust_src / path }} {{ "crates/std/src" / path }} - @perl -i -0777 -pe 's/^\s*#!?\[(un)?stable\(.*?\)\s*\]\n//gsm' {{ "crates/std/src" / path }} - @perl -i -0777 -pe 's/^\s*#!?\[rustc_.*?\]\n//gsm' {{ "crates/std/src" / path }} + @sed -i -f patches.sed {{ "crates/std/src" / path }} update_std: + @# Not copied : sys/mod.rs, io.rs @just cp_std "ffi/c_str.rs" @just cp_std "ffi/mod.rs" @just cp_std "ffi/os_str.rs" + @just cp_std "ffi/os_str/tests.rs" + @just cp_std "sys/env/mod.rs" + @just cp_std "sys/env/unsupported.rs" + @just cp_std "sys/os_str/mod.rs" + @just cp_std "sys/os_str/bytes.rs" + @just cp_std "sys/os_str/bytes/tests.rs" + @# Copied but edited for the moment + # @just cp_std "hash/mod.rs" build_user_prog prog: RUSTFLAGS="-C relocation-model=pic -C link-arg=-Tuser.ld -C link-arg=-pie" cargo b {{ cargo_flags }} --package {{ prog }} diff --git a/patches.sed b/patches.sed new file mode 100644 index 0000000..921f281 --- /dev/null +++ b/patches.sed @@ -0,0 +1,6 @@ +s|crate::bstr::ByteStr|alloc::bstr::ByteStr|g +s|crate::collections::TryReserveError|alloc::collections::TryReserveError|g +s|crate::sync::Arc|alloc::sync::Arc|g + +# Ajouter d'autres modifications facilement ici : +# s|ancien_texte|nouveau_texte|g diff --git a/user/shell/src/main.rs b/user/shell/src/main.rs index c531d7a..d8a5d7a 100644 --- a/user/shell/src/main.rs +++ b/user/shell/src/main.rs @@ -1,3 +1,5 @@ +#![feature(custom_std)] + fn main() -> isize { println!( "Hello from PIC program loaded dynamically with custom std and a better justfile, and syscalls ! " diff --git a/user/test_pic/src/main.rs b/user/test_pic/src/main.rs index a1c2f43..142a42e 100644 --- a/user/test_pic/src/main.rs +++ b/user/test_pic/src/main.rs @@ -1,3 +1,4 @@ +#![feature(custom_std)] #![allow(unused)] use std::{