Skip to content

Rollup of 6 pull requests #113949

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 13 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions library/alloc/src/string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1290,11 +1290,11 @@ impl String {
/// Basic usage:
///
/// ```
/// let mut s = String::from("foo");
/// let mut s = String::from("abč");
///
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('o'));
/// assert_eq!(s.pop(), Some('f'));
/// assert_eq!(s.pop(), Some('č'));
/// assert_eq!(s.pop(), Some('b'));
/// assert_eq!(s.pop(), Some('a'));
///
/// assert_eq!(s.pop(), None);
/// ```
Expand Down Expand Up @@ -1324,11 +1324,11 @@ impl String {
/// Basic usage:
///
/// ```
/// let mut s = String::from("foo");
/// let mut s = String::from("abç");
///
/// assert_eq!(s.remove(0), 'f');
/// assert_eq!(s.remove(1), 'o');
/// assert_eq!(s.remove(0), 'o');
/// assert_eq!(s.remove(0), 'a');
/// assert_eq!(s.remove(1), 'ç');
/// assert_eq!(s.remove(0), 'b');
/// ```
#[inline]
#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
2 changes: 1 addition & 1 deletion library/alloc/src/vec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2961,7 +2961,7 @@ impl<T, A: Allocator> Vec<T, A> {
/// [`copy_from_slice`]: slice::copy_from_slice
#[cfg(not(no_global_oom_handling))]
#[stable(feature = "extend_ref", since = "1.2.0")]
impl<'a, T: Copy + 'a, A: Allocator + 'a> Extend<&'a T> for Vec<T, A> {
impl<'a, T: Copy + 'a, A: Allocator> Extend<&'a T> for Vec<T, A> {
fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
self.spec_extend(iter.into_iter())
}
Expand Down
4 changes: 2 additions & 2 deletions library/alloc/src/vec/spec_extend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<T, A: Allocator> SpecExtend<T, IntoIter<T>> for Vec<T, A> {
}
}

impl<'a, T: 'a, I, A: Allocator + 'a> SpecExtend<&'a T, I> for Vec<T, A>
impl<'a, T: 'a, I, A: Allocator> SpecExtend<&'a T, I> for Vec<T, A>
where
I: Iterator<Item = &'a T>,
T: Clone,
Expand All @@ -46,7 +46,7 @@ where
}
}

impl<'a, T: 'a, A: Allocator + 'a> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
impl<'a, T: 'a, A: Allocator> SpecExtend<&'a T, slice::Iter<'a, T>> for Vec<T, A>
where
T: Copy,
{
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ impl CStr {
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
#[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "101719")]
#[rustc_const_unstable(feature = "const_cstr_from_ptr", issue = "113219")]
pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
Expand Down
5 changes: 0 additions & 5 deletions library/core/src/ffi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,6 @@ macro_rules! type_alias {
}

type_alias! { "c_char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char;
// Make this type alias appear cfg-dependent so that Clippy does not suggest
// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed
// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
// is fixed.
#[cfg(all())]
#[doc(cfg(all()))] }

type_alias! { "c_schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; }
Expand Down
65 changes: 65 additions & 0 deletions library/std/src/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,51 @@ impl 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_os_str_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_os_str_bytes`] can be
/// split either immediately before or immediately after any valid non-empty UTF-8 substring.
///
/// # Example
///
/// ```
/// #![feature(os_str_bytes)]
///
/// use std::ffi::OsStr;
///
/// let os_str = OsStr::new("Mary had a little lamb");
/// let bytes = os_str.as_os_str_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_os_str_bytes`
/// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring
/// unsafe { OsStr::from_os_str_bytes_unchecked(word) }
/// }).collect();
/// ```
///
/// [conversions]: super#conversions
#[inline]
#[unstable(feature = "os_str_bytes", issue = "111544")]
pub unsafe fn from_os_str_bytes_unchecked(bytes: Vec<u8>) -> Self {
OsString { inner: Buf::from_os_str_bytes_unchecked(bytes) }
}

/// Converts to an [`OsStr`] slice.
///
/// # Examples
Expand All @@ -159,6 +204,26 @@ impl OsString {
self
}

/// Converts the `OsString` into a byte slice. To convert the byte slice back into an
/// `OsString`, use the [`OsStr::from_os_str_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]
#[unstable(feature = "os_str_bytes", issue = "111544")]
pub fn into_os_str_bytes(self) -> Vec<u8> {
self.inner.into_os_str_bytes()
}

/// Converts the `OsString` into a [`String`] if it contains valid Unicode data.
///
/// On failure, ownership of the original `OsString` is returned.
Expand Down
5 changes: 0 additions & 5 deletions library/std/src/os/raw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ macro_rules! alias_core_ffi {
($($t:ident)*) => {$(
#[stable(feature = "raw_os", since = "1.1.0")]
#[doc = include_str!(concat!("../../../../core/src/ffi/", stringify!($t), ".md"))]
// Make this type alias appear cfg-dependent so that Clippy does not suggest
// replacing expressions like `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be
// removed after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093
// is fixed.
#[cfg(all())]
#[doc(cfg(all()))]
pub type $t = core::ffi::$t;
)*}
Expand Down
31 changes: 30 additions & 1 deletion library/std/src/os/unix/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,36 @@ pub trait FileExt {
/// Note that similar to [`File::write`], it is not an error to return a
/// short write.
///
/// # Bug
/// On some systems, `write_at` utilises [`pwrite64`] to write to files.
/// However, this syscall has a [bug] where files opened with the `O_APPEND`
/// flag fail to respect the offset parameter, always appending to the end
/// of the file instead.
///
/// It is possible to inadvertantly set this flag, like in the example below.
/// Therefore, it is important to be vigilant while changing options to mitigate
/// unexpected behaviour.
///
/// ```no_run
/// use std::fs::File;
/// use std::io;
/// use std::os::unix::prelude::FileExt;
///
/// fn main() -> io::Result<()> {
/// // Open a file with the append option (sets the `O_APPEND` flag)
/// let file = File::options().append(true).open("foo.txt")?;
///
/// // We attempt to write at offset 10; instead appended to EOF
/// file.write_at(b"sushi", 10)?;
///
/// // foo.txt is 5 bytes long instead of 15
/// Ok(())
/// }
/// ```
///
/// [`File::write`]: fs::File::write
/// [`pwrite64`]: https://man7.org/linux/man-pages/man2/pwrite.2.html
/// [bug]: https://man7.org/linux/man-pages/man2/pwrite.2.html#BUGS
///
/// # Examples
///
Expand All @@ -159,7 +188,7 @@ pub trait FileExt {
/// use std::os::unix::prelude::FileExt;
///
/// fn main() -> io::Result<()> {
/// let file = File::open("foo.txt")?;
/// let file = File::create("foo.txt")?;
///
/// // We now write at the offset 10.
/// file.write_at(b"sushi", 10)?;
Expand Down
10 changes: 10 additions & 0 deletions library/std/src/sys/unix/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,16 @@ impl AsInner<[u8]> for Buf {
}

impl Buf {
#[inline]
pub fn into_os_str_bytes(self) -> Vec<u8> {
self.inner
}

#[inline]
pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self {
Self { inner: s }
}

pub fn from_string(s: String) -> Buf {
Buf { inner: s.into_bytes() }
}
Expand Down
10 changes: 10 additions & 0 deletions library/std/src/sys/windows/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ impl fmt::Display for Slice {
}

impl Buf {
#[inline]
pub fn into_os_str_bytes(self) -> Vec<u8> {
self.inner.into_bytes()
}

#[inline]
pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self {
Self { inner: Wtf8Buf::from_bytes_unchecked(s) }
}

pub fn with_capacity(capacity: usize) -> Buf {
Buf { inner: Wtf8Buf::with_capacity(capacity) }
}
Expand Down
15 changes: 15 additions & 0 deletions library/std/src/sys_common/wtf8.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,15 @@ impl Wtf8Buf {
Wtf8Buf { bytes: Vec::with_capacity(capacity), is_known_utf8: true }
}

/// Creates a WTF-8 string from a WTF-8 byte vec.
///
/// Since the byte vec is not checked for valid WTF-8, this functions is
/// marked unsafe.
#[inline]
pub unsafe fn from_bytes_unchecked(value: Vec<u8>) -> Wtf8Buf {
Wtf8Buf { bytes: value, is_known_utf8: false }
}

/// Creates a WTF-8 string from a UTF-8 `String`.
///
/// This takes ownership of the `String` and does not copy.
Expand Down Expand Up @@ -402,6 +411,12 @@ impl Wtf8Buf {
self.bytes.truncate(new_len)
}

/// Consumes the WTF-8 string and tries to convert it to a vec of bytes.
#[inline]
pub fn into_bytes(self) -> Vec<u8> {
self.bytes
}

/// Consumes the WTF-8 string and tries to convert it to UTF-8.
///
/// This does not copy the data.
Expand Down