Skip to content

Commit

Permalink
Auto merge of rust-lang#95101 - Dylan-DPC:rollup-r1f1v9t, r=Dylan-DPC
Browse files Browse the repository at this point in the history
Rollup of 6 pull requests

Successful merges:

 - rust-lang#92519 (Use verbatim paths for `process::Command` if necessary)
 - rust-lang#92612 (Update stdlib for the l4re target)
 - rust-lang#92663 (Implement `Write for Cursor<[u8; N]>`, plus `A: Allocator` cursor support)
 - rust-lang#93263 (Consistently present absent stdio handles on Windows as NULL handles.)
 - rust-lang#93692 (keyword_docs: document use of `in` with `pub` keyword)
 - rust-lang#94984 (add `CStr` method that accepts any slice containing a nul-terminated string)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
  • Loading branch information
bors committed Mar 19, 2022
2 parents 9b701e7 + 30b4182 commit 3153584
Show file tree
Hide file tree
Showing 18 changed files with 1,159 additions and 114 deletions.
69 changes: 69 additions & 0 deletions library/std/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,27 @@ impl FromVecWithNulError {
}
}

/// An error indicating that no nul byte was present.
///
/// A slice used to create a [`CStr`] must contain a nul byte somewhere
/// within the slice.
///
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
///
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
pub struct FromBytesUntilNulError(());

#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
impl Error for FromBytesUntilNulError {}

#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
impl fmt::Display for FromBytesUntilNulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "data provided does not contain a nul")
}
}

/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
///
/// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
Expand Down Expand Up @@ -1239,12 +1260,60 @@ impl CStr {
}
}

/// Creates a C string wrapper from a byte slice.
///
/// This method will create a `CStr` from any byte slice that contains at
/// least one nul byte. The caller does not need to know or specify where
/// the nul byte is located.
///
/// If the first byte is a nul character, this method will return an
/// empty `CStr`. If multiple nul characters are present, the `CStr` will
/// end at the first one.
///
/// If the slice only has a single nul byte at the end, this method is
/// equivalent to [`CStr::from_bytes_with_nul`].
///
/// # Examples
/// ```
/// #![feature(cstr_from_bytes_until_nul)]
///
/// use std::ffi::CStr;
///
/// let mut buffer = [0u8; 16];
/// unsafe {
/// // Here we might call an unsafe C function that writes a string
/// // into the buffer.
/// let buf_ptr = buffer.as_mut_ptr();
/// buf_ptr.write_bytes(b'A', 8);
/// }
/// // Attempt to extract a C nul-terminated string from the buffer.
/// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
/// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
/// ```
///
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) => {
// SAFETY: We know there is a nul byte at nul_pos, so this slice
// (ending at the nul byte) is a well-formed C string.
let subslice = &bytes[..nul_pos + 1];
Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
}
None => Err(FromBytesUntilNulError(())),
}
}

/// Creates a C string wrapper from a byte slice.
///
/// This function will cast the provided `bytes` to a `CStr`
/// wrapper after ensuring that the byte slice is nul-terminated
/// and does not contain any interior nul bytes.
///
/// If the nul byte may not be at the end,
/// [`CStr::from_bytes_until_nul`] can be used instead.
///
/// # Examples
///
/// ```
Expand Down
37 changes: 37 additions & 0 deletions library/std/src/ffi/c_str/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,43 @@ fn from_bytes_with_nul_interior() {
assert!(cstr.is_err());
}

#[test]
fn cstr_from_bytes_until_nul() {
// Test an empty slice. This should fail because it
// does not contain a nul byte.
let b = b"";
assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));

// Test a non-empty slice, that does not contain a nul byte.
let b = b"hello";
assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));

// Test an empty nul-terminated string
let b = b"\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"");

// Test a slice with the nul byte in the middle
let b = b"hello\0world!";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"hello");

// Test a slice with the nul byte at the end
let b = b"hello\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"hello");

// Test a slice with two nul bytes at the end
let b = b"hello\0\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"hello");

// Test a slice containing lots of nul bytes
let b = b"\0\0\0\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"");
}

#[test]
fn into_boxed() {
let orig: &[u8] = b"Hello, world!\0";
Expand Down
53 changes: 46 additions & 7 deletions library/std/src/io/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod tests;

use crate::io::prelude::*;

use crate::alloc::Allocator;
use crate::cmp;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};

Expand Down Expand Up @@ -398,7 +399,10 @@ fn slice_write_vectored(
}

// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
where
A: Allocator,
{
let pos: usize = (*pos_mut).try_into().map_err(|_| {
io::const_io_error!(
ErrorKind::InvalidInput,
Expand Down Expand Up @@ -426,11 +430,14 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi
Ok(buf.len())
}

fn vec_write_vectored(
fn vec_write_vectored<A>(
pos_mut: &mut u64,
vec: &mut Vec<u8>,
vec: &mut Vec<u8, A>,
bufs: &[IoSlice<'_>],
) -> io::Result<usize> {
) -> io::Result<usize>
where
A: Allocator,
{
let mut nwritten = 0;
for buf in bufs {
nwritten += vec_write(pos_mut, vec, buf)?;
Expand Down Expand Up @@ -462,7 +469,10 @@ impl Write for Cursor<&mut [u8]> {
}

#[stable(feature = "cursor_mut_vec", since = "1.25.0")]
impl Write for Cursor<&mut Vec<u8>> {
impl<A> Write for Cursor<&mut Vec<u8, A>>
where
A: Allocator,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
Expand All @@ -483,7 +493,10 @@ impl Write for Cursor<&mut Vec<u8>> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Cursor<Vec<u8>> {
impl<A> Write for Cursor<Vec<u8, A>>
where
A: Allocator,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
Expand All @@ -504,7 +517,33 @@ impl Write for Cursor<Vec<u8>> {
}

#[stable(feature = "cursor_box_slice", since = "1.5.0")]
impl Write for Cursor<Box<[u8]>> {
impl<A> Write for Cursor<Box<[u8], A>>
where
A: Allocator,
{
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
}

#[inline]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
}

#[inline]
fn is_write_vectored(&self) -> bool {
true
}

#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

#[stable(feature = "cursor_array", since = "1.61.0")]
impl<const N: usize> Write for Cursor<[u8; N]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
Expand Down
84 changes: 40 additions & 44 deletions library/std/src/io/cursor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ fn test_mem_mut_writer() {
assert_eq!(&writer.get_ref()[..], b);
}

#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
fn test_slice_writer<T>(writer: &mut Cursor<T>)
where
T: AsRef<[u8]>,
Cursor<T>: Write,
{
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
Expand All @@ -65,12 +67,14 @@ fn test_box_slice_writer() {
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
assert_eq!(writer.get_ref().as_ref(), b);
}

#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
fn test_slice_writer_vectored<T>(writer: &mut Cursor<T>)
where
T: AsRef<[u8]>,
Cursor<T>: Write,
{
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
Expand All @@ -85,53 +89,45 @@ fn test_box_slice_writer_vectored() {
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
assert_eq!(writer.get_ref().as_ref(), b);
}

#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
test_slice_writer(&mut writer);
}

#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
test_slice_writer_vectored(&mut writer);
}

#[test]
fn test_array_writer() {
let mut writer = Cursor::new([0u8; 9]);
test_slice_writer(&mut writer);
}

#[test]
fn test_array_writer_vectored() {
let mut writer = Cursor::new([0u8; 9]);
test_slice_writer_vectored(&mut writer);
}

#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);

assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
let mut writer = Cursor::new(&mut buf[..]);
test_slice_writer(&mut writer);
}

#[test]
fn test_buf_writer_vectored() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);

assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
let mut writer = Cursor::new(&mut buf[..]);
test_slice_writer_vectored(&mut writer);
}

#[test]
Expand Down
Loading

0 comments on commit 3153584

Please sign in to comment.