Skip to content

Commit

Permalink
Distinguish the ways CStr::from_bytes_with_nul can fail
Browse files Browse the repository at this point in the history
  • Loading branch information
tbu- committed Mar 9, 2017
1 parent b04ebef commit da6e7c8
Showing 1 changed file with 40 additions and 6 deletions.
46 changes: 40 additions & 6 deletions src/libstd/ffi/c_str.rs
Expand Up @@ -154,7 +154,28 @@ pub struct NulError(usize, Vec<u8>);
/// byte was found too early in the slice provided or one wasn't found at all.
#[derive(Clone, PartialEq, Eq, Debug)]
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub struct FromBytesWithNulError { _a: () }
pub struct FromBytesWithNulError {
kind: FromBytesWithNulErrorKind,
}

#[derive(Clone, PartialEq, Eq, Debug)]
enum FromBytesWithNulErrorKind {
InteriorNul(usize),
NotNulTerminated,
}

impl FromBytesWithNulError {
fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError {
kind: FromBytesWithNulErrorKind::InteriorNul(pos),
}
}
fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError {
kind: FromBytesWithNulErrorKind::NotNulTerminated,
}
}
}

/// An error returned from `CString::into_string` to indicate that a UTF-8 error
/// was encountered during the conversion.
Expand Down Expand Up @@ -458,14 +479,23 @@ impl From<NulError> for io::Error {
#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
impl Error for FromBytesWithNulError {
fn description(&self) -> &str {
"data provided is not null terminated or contains an interior nul byte"
match self.kind {
FromBytesWithNulErrorKind::InteriorNul(..) =>
"data provided contains an interior nul byte",
FromBytesWithNulErrorKind::NotNulTerminated =>
"data provided is not nul terminated",
}
}
}

#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")]
impl fmt::Display for FromBytesWithNulError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.description().fmt(f)
f.write_str(self.description())?;
if let FromBytesWithNulErrorKind::InteriorNul(pos) = self.kind {
write!(f, " at byte pos {}", pos)?;
}
Ok(())
}
}

Expand Down Expand Up @@ -559,10 +589,14 @@ impl CStr {
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
pub fn from_bytes_with_nul(bytes: &[u8])
-> Result<&CStr, FromBytesWithNulError> {
if bytes.is_empty() || memchr::memchr(0, &bytes) != Some(bytes.len() - 1) {
Err(FromBytesWithNulError { _a: () })
let nul_pos = memchr::memchr(0, bytes);
if let Some(nul_pos) = nul_pos {
if nul_pos + 1 != bytes.len() {
return Err(FromBytesWithNulError::interior_nul(nul_pos));
}
Ok(unsafe { CStr::from_bytes_with_nul_unchecked(bytes) })
} else {
Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
Err(FromBytesWithNulError::not_nul_terminated())
}
}

Expand Down

0 comments on commit da6e7c8

Please sign in to comment.