1
Fork 0

Rollup merge of #29775 - arcnmx:raw-c_char, r=alexcrichton

It's a bit strange to expect users of `libstd` to require the use of an external crates.io crate to work with standard types. This commit encourages the use `os::raw::c_char` instead, although users are certainly free to use `libc::c_char` if they wish; the test still exists to ensure the two types are identical (though the reported bug only exists on platforms that are not officially tested).

Fixes #29774
This commit is contained in:
Manish Goregaokar 2015-11-12 00:59:30 +05:30
commit 3ef3fd96cf
2 changed files with 38 additions and 42 deletions

View file

@ -21,6 +21,7 @@ use libc;
use mem; use mem;
use ops::Deref; use ops::Deref;
use option::Option::{self, Some, None}; use option::Option::{self, Some, None};
use os::raw::c_char;
use result::Result::{self, Ok, Err}; use result::Result::{self, Ok, Err};
use slice; use slice;
use str::{self, Utf8Error}; use str::{self, Utf8Error};
@ -36,23 +37,20 @@ use vec::Vec;
/// ///
/// A `CString` is created from either a byte slice or a byte vector. After /// A `CString` is created from either a byte slice or a byte vector. After
/// being created, a `CString` predominately inherits all of its methods from /// being created, a `CString` predominately inherits all of its methods from
/// the `Deref` implementation to `[libc::c_char]`. Note that the underlying /// the `Deref` implementation to `[c_char]`. Note that the underlying array
/// array is represented as an array of `libc::c_char` as opposed to `u8`. A /// is represented as an array of `c_char` as opposed to `u8`. A `u8` slice
/// `u8` slice can be obtained with the `as_bytes` method. Slices produced from /// can be obtained with the `as_bytes` method. Slices produced from a `CString`
/// a `CString` do *not* contain the trailing nul terminator unless otherwise /// do *not* contain the trailing nul terminator unless otherwise specified.
/// specified.
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # #![feature(libc)]
/// # extern crate libc;
/// # fn main() { /// # fn main() {
/// use std::ffi::CString; /// use std::ffi::CString;
/// use libc; /// use std::os::raw::c_char;
/// ///
/// extern { /// extern {
/// fn my_printer(s: *const libc::c_char); /// fn my_printer(s: *const c_char);
/// } /// }
/// ///
/// let c_to_print = CString::new("Hello, world!").unwrap(); /// let c_to_print = CString::new("Hello, world!").unwrap();
@ -83,11 +81,10 @@ pub struct CString {
/// Inspecting a foreign C string /// Inspecting a foreign C string
/// ///
/// ```no_run /// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::ffi::CStr; /// use std::ffi::CStr;
/// use std::os::raw::c_char;
/// ///
/// extern { fn my_string() -> *const libc::c_char; } /// extern { fn my_string() -> *const c_char; }
/// ///
/// fn main() { /// fn main() {
/// unsafe { /// unsafe {
@ -100,12 +97,11 @@ pub struct CString {
/// Passing a Rust-originating C string /// Passing a Rust-originating C string
/// ///
/// ```no_run /// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::ffi::{CString, CStr}; /// use std::ffi::{CString, CStr};
/// use std::os::raw::c_char;
/// ///
/// fn work(data: &CStr) { /// fn work(data: &CStr) {
/// extern { fn work_with(data: *const libc::c_char); } /// extern { fn work_with(data: *const c_char); }
/// ///
/// unsafe { work_with(data.as_ptr()) } /// unsafe { work_with(data.as_ptr()) }
/// } /// }
@ -119,11 +115,10 @@ pub struct CString {
/// Converting a foreign C string into a Rust `String` /// Converting a foreign C string into a Rust `String`
/// ///
/// ```no_run /// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::ffi::CStr; /// use std::ffi::CStr;
/// use std::os::raw::c_char;
/// ///
/// extern { fn my_string() -> *const libc::c_char; } /// extern { fn my_string() -> *const c_char; }
/// ///
/// fn my_string_safe() -> String { /// fn my_string_safe() -> String {
/// unsafe { /// unsafe {
@ -139,10 +134,10 @@ pub struct CString {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct CStr { pub struct CStr {
// FIXME: this should not be represented with a DST slice but rather with // FIXME: this should not be represented with a DST slice but rather with
// just a raw `libc::c_char` along with some form of marker to make // just a raw `c_char` along with some form of marker to make
// this an unsized type. Essentially `sizeof(&CStr)` should be the // this an unsized type. Essentially `sizeof(&CStr)` should be the
// same as `sizeof(&c_char)` but `CStr` should be an unsized type. // same as `sizeof(&c_char)` but `CStr` should be an unsized type.
inner: [libc::c_char] inner: [c_char]
} }
/// An error returned from `CString::new` to indicate that a nul byte was found /// An error returned from `CString::new` to indicate that a nul byte was found
@ -169,11 +164,10 @@ impl CString {
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::ffi::CString; /// use std::ffi::CString;
/// use std::os::raw::c_char;
/// ///
/// extern { fn puts(s: *const libc::c_char); } /// extern { fn puts(s: *const c_char); }
/// ///
/// fn main() { /// fn main() {
/// let to_print = CString::new("Hello!").unwrap(); /// let to_print = CString::new("Hello!").unwrap();
@ -220,7 +214,7 @@ impl CString {
#[unstable(feature = "cstr_memory2", reason = "recently added", #[unstable(feature = "cstr_memory2", reason = "recently added",
issue = "27769")] issue = "27769")]
#[deprecated(since = "1.4.0", reason = "renamed to from_raw")] #[deprecated(since = "1.4.0", reason = "renamed to from_raw")]
pub unsafe fn from_ptr(ptr: *const libc::c_char) -> CString { pub unsafe fn from_ptr(ptr: *const c_char) -> CString {
CString::from_raw(ptr as *mut _) CString::from_raw(ptr as *mut _)
} }
@ -230,7 +224,7 @@ impl CString {
/// `into_raw`. The length of the string will be recalculated /// `into_raw`. The length of the string will be recalculated
/// using the pointer. /// using the pointer.
#[stable(feature = "cstr_memory", since = "1.4.0")] #[stable(feature = "cstr_memory", since = "1.4.0")]
pub unsafe fn from_raw(ptr: *mut libc::c_char) -> CString { pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
let len = libc::strlen(ptr) + 1; // Including the NUL byte let len = libc::strlen(ptr) + 1; // Including the NUL byte
let slice = slice::from_raw_parts(ptr, len as usize); let slice = slice::from_raw_parts(ptr, len as usize);
CString { inner: mem::transmute(slice) } CString { inner: mem::transmute(slice) }
@ -247,7 +241,7 @@ impl CString {
#[unstable(feature = "cstr_memory2", reason = "recently added", #[unstable(feature = "cstr_memory2", reason = "recently added",
issue = "27769")] issue = "27769")]
#[deprecated(since = "1.4.0", reason = "renamed to into_raw")] #[deprecated(since = "1.4.0", reason = "renamed to into_raw")]
pub fn into_ptr(self) -> *const libc::c_char { pub fn into_ptr(self) -> *const c_char {
self.into_raw() as *const _ self.into_raw() as *const _
} }
@ -260,8 +254,8 @@ impl CString {
/// ///
/// Failure to call `from_raw` will lead to a memory leak. /// Failure to call `from_raw` will lead to a memory leak.
#[stable(feature = "cstr_memory", since = "1.4.0")] #[stable(feature = "cstr_memory", since = "1.4.0")]
pub fn into_raw(self) -> *mut libc::c_char { pub fn into_raw(self) -> *mut c_char {
Box::into_raw(self.inner) as *mut libc::c_char Box::into_raw(self.inner) as *mut c_char
} }
/// Converts the `CString` into a `String` if it contains valid Unicode data. /// Converts the `CString` into a `String` if it contains valid Unicode data.
@ -426,15 +420,13 @@ impl CStr {
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// # #![feature(libc)]
/// # extern crate libc;
/// # fn main() { /// # fn main() {
/// use std::ffi::CStr; /// use std::ffi::CStr;
/// use std::os::raw::c_char;
/// use std::str; /// use std::str;
/// use libc;
/// ///
/// extern { /// extern {
/// fn my_string() -> *const libc::c_char; /// fn my_string() -> *const c_char;
/// } /// }
/// ///
/// unsafe { /// unsafe {
@ -445,7 +437,7 @@ impl CStr {
/// # } /// # }
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const libc::c_char) -> &'a CStr { pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
let len = libc::strlen(ptr); let len = libc::strlen(ptr);
mem::transmute(slice::from_raw_parts(ptr, len as usize + 1)) mem::transmute(slice::from_raw_parts(ptr, len as usize + 1))
} }
@ -456,7 +448,7 @@ impl CStr {
/// to a contiguous region of memory terminated with a 0 byte to represent /// to a contiguous region of memory terminated with a 0 byte to represent
/// the end of the string. /// the end of the string.
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn as_ptr(&self) -> *const libc::c_char { pub fn as_ptr(&self) -> *const c_char {
self.inner.as_ptr() self.inner.as_ptr()
} }
@ -560,14 +552,14 @@ impl ToOwned for CStr {
mod tests { mod tests {
use prelude::v1::*; use prelude::v1::*;
use super::*; use super::*;
use libc; use os::raw::c_char;
use borrow::Cow::{Borrowed, Owned}; use borrow::Cow::{Borrowed, Owned};
use hash::{SipHasher, Hash, Hasher}; use hash::{SipHasher, Hash, Hasher};
#[test] #[test]
fn c_to_rust() { fn c_to_rust() {
let data = b"123\0"; let data = b"123\0";
let ptr = data.as_ptr() as *const libc::c_char; let ptr = data.as_ptr() as *const c_char;
unsafe { unsafe {
assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123");
assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0");
@ -616,13 +608,13 @@ mod tests {
#[test] #[test]
fn to_str() { fn to_str() {
let data = b"123\xE2\x80\xA6\0"; let data = b"123\xE2\x80\xA6\0";
let ptr = data.as_ptr() as *const libc::c_char; let ptr = data.as_ptr() as *const c_char;
unsafe { unsafe {
assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…"));
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…"));
} }
let data = b"123\xE2\0"; let data = b"123\xE2\0";
let ptr = data.as_ptr() as *const libc::c_char; let ptr = data.as_ptr() as *const c_char;
unsafe { unsafe {
assert!(CStr::from_ptr(ptr).to_str().is_err()); assert!(CStr::from_ptr(ptr).to_str().is_err());
assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}"))); assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::<str>(format!("123\u{FFFD}")));
@ -632,7 +624,7 @@ mod tests {
#[test] #[test]
fn to_owned() { fn to_owned() {
let data = b"123\0"; let data = b"123\0";
let ptr = data.as_ptr() as *const libc::c_char; let ptr = data.as_ptr() as *const c_char;
let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; let owned = unsafe { CStr::from_ptr(ptr).to_owned() };
assert_eq!(owned.as_bytes_with_nul(), data); assert_eq!(owned.as_bytes_with_nul(), data);
@ -641,7 +633,7 @@ mod tests {
#[test] #[test]
fn equal_hash() { fn equal_hash() {
let data = b"123\xE2\xFA\xA6\0"; let data = b"123\xE2\xFA\xA6\0";
let ptr = data.as_ptr() as *const libc::c_char; let ptr = data.as_ptr() as *const c_char;
let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) };
let mut s = SipHasher::new_with_keys(0, 0); let mut s = SipHasher::new_with_keys(0, 0);

View file

@ -12,9 +12,13 @@
#![stable(feature = "raw_os", since = "1.1.0")] #![stable(feature = "raw_os", since = "1.1.0")]
#[cfg(any(target_arch = "aarch64", target_os = "android"))] #[cfg(any(target_os = "android",
all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "arm"))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = u8;
#[cfg(not(any(target_arch = "aarch64", target_os = "android")))] #[cfg(not(any(target_os = "android",
all(target_os = "linux", any(target_arch = "aarch64",
target_arch = "arm")))))]
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_char = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_schar = i8;
#[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8; #[stable(feature = "raw_os", since = "1.1.0")] pub type c_uchar = u8;