From e610a52a6259cae4c9f3ebdb6016e68b507878e4 Mon Sep 17 00:00:00 2001 From: George Bateman Date: Wed, 1 May 2024 19:28:45 +0100 Subject: [PATCH] Describe and use CStr literals in CStr and CString docs --- library/alloc/src/ffi/c_str.rs | 14 +++++--------- library/core/src/ffi/c_str.rs | 35 ++++++++++++++++++++++------------ 2 files changed, 28 insertions(+), 21 deletions(-) diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index 6a64eaf576bb9..f143e5578717f 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -41,6 +41,7 @@ use crate::sync::Arc; /// or anything that implements [Into]<[Vec]<[u8]>> (for /// example, you can build a `CString` straight out of a [`String`] or /// a &[str], 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 &[[u8]] /// does not have 0 bytes in the middle, and return an error if it @@ -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".to_string_lossy(), /// Cow::Owned(String::from("Hello �World")) as Cow<'_, str> /// ); /// ``` diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index f4f33f8584bd0..9d914d798eb22 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -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 &[[u8]] -/// slice, or unsafely from a raw `*const c_char`. It can then be -/// converted to a Rust &[str] 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 &[str] by performing +/// UTF-8 validation, or into an owned `CString`. /// /// `&CStr` is to `CString` as &[str] 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()); @@ -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()) } /// } @@ -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()) }; @@ -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 { @@ -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 @@ -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(()) /// # } /// ```