From cb48d4458377904103ca0254bf9270ee1a2426be Mon Sep 17 00:00:00 2001 From: arcnmx Date: Sun, 11 Oct 2015 19:49:57 -0400 Subject: [PATCH] Owned conversions for CString --- src/libstd/ffi/c_str.rs | 72 ++++++++++++++++++++++++++++++++++++++++- src/libstd/ffi/mod.rs | 2 +- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index 6b7ecaa77d1..89427f7851b 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -23,7 +23,7 @@ use ops::Deref; use option::Option::{self, Some, None}; use result::Result::{self, Ok, Err}; use slice; -use str; +use str::{self, Utf8Error}; use string::String; use vec::Vec; @@ -151,6 +151,15 @@ pub struct CStr { #[stable(feature = "rust1", since = "1.0.0")] pub struct NulError(usize, Vec); +/// An error returned from `CString::into_string` to indicate that a UTF-8 error +/// was encountered during the conversion. +#[derive(Clone, PartialEq, Debug)] +#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] +pub struct IntoStringError { + inner: CString, + error: Utf8Error, +} + impl CString { /// Creates a new C-compatible string from a container of bytes. /// @@ -255,6 +264,38 @@ impl CString { Box::into_raw(self.inner) as *mut libc::c_char } + /// Converts the `CString` into a `String` if it contains valid Unicode data. + /// + /// On failure, ownership of the original `CString` is returned. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_string(self) -> Result { + String::from_utf8(self.into_bytes()) + .map_err(|e| IntoStringError { + error: e.utf8_error(), + inner: unsafe { CString::from_vec_unchecked(e.into_bytes()) }, + }) + } + + /// Returns the underlying byte buffer. + /// + /// The returned buffer does **not** contain the trailing nul separator and + /// it is guaranteed to not have any interior nul bytes. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_bytes(self) -> Vec { + // FIXME: Once this method becomes stable, add an `impl Into> for CString` + let mut vec = self.inner.into_vec(); + let _nul = vec.pop(); + debug_assert_eq!(_nul, Some(0u8)); + vec + } + + /// Equivalent to the `into_bytes` function except that the returned vector + /// includes the trailing nul byte. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_bytes_with_nul(self) -> Vec { + self.inner.into_vec() + } + /// Returns the contents of this `CString` as a slice of bytes. /// /// The returned slice does **not** contain the trailing nul separator and @@ -336,6 +377,35 @@ impl From for io::Error { } } +impl IntoStringError { + /// Consumes this error, returning original `CString` which generated the + /// error. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn into_cstring(self) -> CString { + self.inner + } + + /// Access the underlying UTF-8 error that was the cause of this error. + #[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] + pub fn utf8_error(&self) -> Utf8Error { + self.error + } +} + +#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] +impl Error for IntoStringError { + fn description(&self) -> &str { + Error::description(&self.error) + } +} + +#[unstable(feature = "cstring_into", reason = "recently added", issue = "29157")] +impl fmt::Display for IntoStringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.error, f) + } +} + impl CStr { /// Casts a raw C string to a safe C string wrapper. /// diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs index dfe706e0773..bfd6ab52289 100644 --- a/src/libstd/ffi/mod.rs +++ b/src/libstd/ffi/mod.rs @@ -13,7 +13,7 @@ #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -pub use self::c_str::{CString, CStr, NulError}; +pub use self::c_str::{CString, CStr, NulError, IntoStringError}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::os_str::{OsString, OsStr};