Auto merge of #30614 - arcnmx:cstr-bytes, r=alexcrichton
I'm a bit iffy on the return type, but `Result` would also be a bit weird... The two error cases are `Unterminated` and `InteriorNul(usize)`. I considered `from_chars(&[c_char])` but this meshes better with `as_bytes_with_nul()` and Rust code in general. Should there also be a corresponding unsafe `from_bytes_unchecked` variant?
This commit is contained in:
commit
281f9d868f
1 changed files with 78 additions and 0 deletions
|
|
@ -436,6 +436,57 @@ impl CStr {
|
|||
mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
|
||||
}
|
||||
|
||||
/// Creates a C string wrapper from a byte slice.
|
||||
///
|
||||
/// This function will cast the provided `bytes` to a `CStr` wrapper after
|
||||
/// ensuring that it is null terminated and does not contain any interior
|
||||
/// nul bytes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(cstr_from_bytes)]
|
||||
/// use std::ffi::CStr;
|
||||
///
|
||||
/// # fn main() {
|
||||
/// let cstr = CStr::from_bytes_with_nul(b"hello\0");
|
||||
/// assert!(cstr.is_some());
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "cstr_from_bytes", reason = "recently added", issue = "31190")]
|
||||
pub fn from_bytes_with_nul(bytes: &[u8]) -> Option<&CStr> {
|
||||
if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) {
|
||||
None
|
||||
} else {
|
||||
Some(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
|
||||
}
|
||||
}
|
||||
|
||||
/// Unsafely creates a C string wrapper from a byte slice.
|
||||
///
|
||||
/// This function will cast the provided `bytes` to a `CStr` wrapper without
|
||||
/// performing any sanity checks. The provided slice must be null terminated
|
||||
/// and not contain any interior nul bytes.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # #![feature(cstr_from_bytes)]
|
||||
/// use std::ffi::{CStr, CString};
|
||||
///
|
||||
/// # fn main() {
|
||||
/// unsafe {
|
||||
/// let cstring = CString::new("hello").unwrap();
|
||||
/// let cstr = CStr::from_bytes_with_nul_unchecked(cstring.to_bytes_with_nul());
|
||||
/// assert_eq!(cstr, &*cstring);
|
||||
/// }
|
||||
/// # }
|
||||
/// ```
|
||||
#[unstable(feature = "cstr_from_bytes", reason = "recently added", issue = "31190")]
|
||||
pub unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
|
||||
mem::transmute(bytes)
|
||||
}
|
||||
|
||||
/// Returns the inner pointer to this C string.
|
||||
///
|
||||
/// The returned pointer will be valid for as long as `self` is and points
|
||||
|
|
@ -670,4 +721,31 @@ mod tests {
|
|||
|
||||
assert_eq!(cstr_hash, cstring_hash);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_bytes_with_nul() {
|
||||
let data = b"123\0";
|
||||
let cstr = CStr::from_bytes_with_nul(data);
|
||||
assert_eq!(cstr.map(CStr::to_bytes), Some(&b"123"[..]));
|
||||
assert_eq!(cstr.map(CStr::to_bytes_with_nul), Some(&b"123\0"[..]));
|
||||
|
||||
unsafe {
|
||||
let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data);
|
||||
assert_eq!(cstr, Some(cstr_unchecked));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_bytes_with_nul_unterminated() {
|
||||
let data = b"123";
|
||||
let cstr = CStr::from_bytes_with_nul(data);
|
||||
assert!(cstr.is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_bytes_with_nul_interior() {
|
||||
let data = b"1\023\0";
|
||||
let cstr = CStr::from_bytes_with_nul(data);
|
||||
assert!(cstr.is_none());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue