Skip to content

Commit

Permalink
Describe and use CStr literals in CStr and CString docs
Browse files Browse the repository at this point in the history
  • Loading branch information
GKFX committed May 1, 2024
1 parent 20aa2d8 commit 5f38ed4
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 21 deletions.
14 changes: 5 additions & 9 deletions library/alloc/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ use crate::sync::Arc;
/// or anything that implements <code>[Into]<[Vec]<[u8]>></code> (for
/// example, you can build a `CString` straight out of a [`String`] or
/// a <code>&[str]</code>, since both implement that trait).
/// You can create a `CString` from a literal with `CString::from(c"Text")`.
///
/// The [`CString::new`] method will actually check that the provided <code>&[[u8]]</code>
/// does not have 0 bytes in the middle, and return an error if it
Expand Down Expand Up @@ -1069,27 +1070,22 @@ impl CStr {
///
/// # Examples
///
/// Calling `to_string_lossy` on a `CStr` containing valid UTF-8:
/// Calling `to_string_lossy` on a `CStr` containing valid UTF-8. The leading
/// `c` on the string literal denotes a `CStr`.
///
/// ```
/// use std::borrow::Cow;
/// use std::ffi::CStr;
///
/// let cstr = CStr::from_bytes_with_nul(b"Hello World\0")
/// .expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(cstr.to_string_lossy(), Cow::Borrowed("Hello World"));
/// assert_eq!(c"Hello World".to_string_lossy(), Cow::Borrowed("Hello World"));
/// ```
///
/// Calling `to_string_lossy` on a `CStr` containing invalid UTF-8:
///
/// ```
/// use std::borrow::Cow;
/// use std::ffi::CStr;
///
/// let cstr = CStr::from_bytes_with_nul(b"Hello \xF0\x90\x80World\0")
/// .expect("CStr::from_bytes_with_nul failed");
/// assert_eq!(
/// cstr.to_string_lossy(),
/// c"Hello \xF0\x90\x80World",
/// Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
/// );
/// ```
Expand Down
35 changes: 23 additions & 12 deletions library/core/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,28 +23,32 @@ use crate::str;
///
/// This type represents a borrowed reference to a nul-terminated
/// array of bytes. It can be constructed safely from a <code>&[[u8]]</code>
/// slice, or unsafely from a raw `*const c_char`. It can then be
/// converted to a Rust <code>&[str]</code> by performing UTF-8 validation, or
/// into an owned `CString`.
/// slice, or unsafely from a raw `*const c_char`. It can be expressed as a
/// literal in the form `c"Hello world"`.
///
/// The `CStr` can then be converted to a Rust <code>&[str]</code> by performing
/// UTF-8 validation, or into an owned `CString`.
///
/// `&CStr` is to `CString` as <code>&[str]</code> is to `String`: the former
/// in each pair are borrowed references; the latter are owned
/// strings.
///
/// Note that this structure does **not** have a guaranteed layout (the `repr(transparent)`
/// notwithstanding) and is not recommended to be placed in the signatures of FFI functions.
/// Instead, safe wrappers of FFI functions may leverage the unsafe [`CStr::from_ptr`] constructor
/// to provide a safe interface to other consumers.
/// notwithstanding) and should not be placed in the signatures of FFI functions.
/// Instead, safe wrappers of FFI functions may leverage [`CStr::as_ptr`] and the unsafe
/// [`CStr::from_ptr`] constructor to provide a safe interface to other consumers.
///
/// # Examples
///
/// Inspecting a foreign C string:
///
/// ```ignore (extern-declaration)
/// ```
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn my_string() -> *const c_char; }
/// # unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() }
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
Expand All @@ -54,12 +58,14 @@ use crate::str;
///
/// Passing a Rust-originating C string:
///
/// ```ignore (extern-declaration)
/// ```
/// use std::ffi::{CString, CStr};
/// use std::os::raw::c_char;
///
/// fn work(data: &CStr) {
/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn work_with(data: *const c_char); }
/// # unsafe extern "C" fn work_with(s: *const c_char) {}
///
/// unsafe { work_with(data.as_ptr()) }
/// }
Expand All @@ -70,11 +76,13 @@ use crate::str;
///
/// Converting a foreign C string into a Rust `String`:
///
/// ```ignore (extern-declaration)
/// ```
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// # #[cfg(any())] // Extern functions are awkward in doc comments - fake it instead
/// extern "C" { fn my_string() -> *const c_char; }
/// # unsafe extern "C" fn my_string() -> *const c_char { c"hello".as_ptr() }
///
/// fn my_string_safe() -> String {
/// let cstr = unsafe { CStr::from_ptr(my_string()) };
Expand Down Expand Up @@ -241,11 +249,11 @@ impl CStr {
///
/// # Examples
///
/// ```ignore (extern-declaration)
/// ```
/// use std::ffi::{c_char, CStr};
///
/// extern "C" {
/// fn my_string() -> *const c_char;
/// fn my_string() -> *const c_char {
/// c"hello".as_ptr()
/// }
///
/// unsafe {
Expand All @@ -264,6 +272,8 @@ impl CStr {
/// BYTES.as_ptr().cast()
/// };
/// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
///
/// assert_eq!(c"Hello, world!", HELLO);
/// ```
///
/// [valid]: core::ptr#safety
Expand Down Expand Up @@ -549,6 +559,7 @@ impl CStr {
///
/// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
/// assert!(empty_cstr.is_empty());
/// assert!(c"".is_empty());
/// # Ok(())
/// # }
/// ```
Expand Down

0 comments on commit 5f38ed4

Please sign in to comment.