Skip to content
Merged
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
83 changes: 82 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#![cfg_attr(not(feature = "std"), no_std)]
#![warn(rust_2018_idioms)]
#![cfg_attr(feature = "nightly", feature(const_raw_ptr_deref))]
#![cfg_attr(feature = "nightly", feature(const_slice_from_raw_parts))]
#![cfg_attr(feature = "nightly", feature(const_str_from_utf8))]

#[cfg(test)]
extern crate std;
Expand Down Expand Up @@ -1155,11 +1157,40 @@ impl CStr {
/// assert_eq!(cstr.to_bytes(), b"foo");
/// ```
#[inline]
#[cfg(not(feature = "nightly"))]
pub fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
&bytes[..bytes.len() - 1]
}

/// Converts this C string to a byte slice.
///
/// The returned slice will **not** contain the trailing nul terminator that this C
/// string has.
///
/// > **Note**: This method is currently implemented as a constant-time
/// > cast, but it is planned to alter its definition in the future to
/// > perform the length calculation whenever this method is called.
///
/// # Examples
///
/// ```
/// use cstr_core::CStr;
///
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(cstr.to_bytes(), b"foo");
/// ```
#[inline]
#[cfg(feature = "nightly")]
pub const fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
// unsafe: This is just like [:len - 1] (but const usable), and any underflow of the `- 1`
// is avoided by the type's guarantee that there is a trailing nul byte.
unsafe {
slice::from_raw_parts(bytes.as_ptr(), bytes.len() - 1)
}
}

/// Converts this C string to a byte slice containing the trailing 0 byte.
///
/// This function is the equivalent of [`to_bytes`] except that it will retain
Expand All @@ -1180,6 +1211,32 @@ impl CStr {
/// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
/// ```
#[inline]
#[cfg(feature = "nightly")]
pub const fn to_bytes_with_nul(&self) -> &[u8] {
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
}

/// Converts this C string to a byte slice containing the trailing 0 byte.
///
/// This function is the equivalent of [`to_bytes`] except that it will retain
/// the trailing nul terminator instead of chopping it off.
///
/// > **Note**: This method is currently implemented as a 0-cost cast, but
/// > it is planned to alter its definition in the future to perform the
/// > length calculation whenever this method is called.
///
/// [`to_bytes`]: #method.to_bytes
///
/// # Examples
///
/// ```
/// use cstr_core::CStr;
///
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(cstr.to_bytes_with_nul(), b"foo\0");
/// ```
#[inline]
#[cfg(not(feature = "nightly"))]
pub fn to_bytes_with_nul(&self) -> &[u8] {
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
}
Expand All @@ -1198,7 +1255,31 @@ impl CStr {
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
pub fn to_str(&self) -> Result<&str, Utf8Error> {
#[cfg(not(feature = "nightly"))]
pub fn to_str(&self) -> Result<&str, Utf8Error> {
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
// instead of in `from_ptr()`, it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation
// instead of doing it afterwards.
str::from_utf8(self.to_bytes())
}

/// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
///
/// If the contents of the `CStr` are valid UTF-8 data, this
/// function will return the corresponding [`&str`] slice. Otherwise,
/// it will return an error with details of where UTF-8 validation failed.
///
/// # Examples
///
/// ```
/// use cstr_core::CStr;
///
/// let cstr = CStr::from_bytes_with_nul(b"foo\0").expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
#[cfg(feature = "nightly")]
pub const fn to_str(&self) -> Result<&str, Utf8Error> {
// N.B., when `CStr` is changed to perform the length check in `.to_bytes()`
// instead of in `from_ptr()`, it may be worth considering if this should
// be rewritten to do the UTF-8 check inline with the length calculation
Expand Down