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:
bors 2016-02-23 20:08:54 +00:00
commit 281f9d868f

View file

@ -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());
}
}