summaryrefslogtreecommitdiffstats
path: root/library/core/src/ffi
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--library/core/src/ffi/c_double.md4
-rw-r--r--library/core/src/ffi/c_float.md4
-rw-r--r--library/core/src/ffi/c_str.rs105
3 files changed, 84 insertions, 29 deletions
diff --git a/library/core/src/ffi/c_double.md b/library/core/src/ffi/c_double.md
index 57f453482..d49e29b6e 100644
--- a/library/core/src/ffi/c_double.md
+++ b/library/core/src/ffi/c_double.md
@@ -1,6 +1,6 @@
Equivalent to C's `double` type.
-This type will almost always be [`f64`], which is guaranteed to be an [IEEE-754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
+This type will almost always be [`f64`], which is guaranteed to be an [IEEE 754 double-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number with at least the precision of a [`float`], and it may be `f32` or something entirely different from the IEEE-754 standard.
-[IEEE-754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[IEEE 754 double-precision float]: https://en.wikipedia.org/wiki/IEEE_754
[`float`]: c_float
diff --git a/library/core/src/ffi/c_float.md b/library/core/src/ffi/c_float.md
index 61e2abc05..36374ef43 100644
--- a/library/core/src/ffi/c_float.md
+++ b/library/core/src/ffi/c_float.md
@@ -1,5 +1,5 @@
Equivalent to C's `float` type.
-This type will almost always be [`f32`], which is guaranteed to be an [IEEE-754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
+This type will almost always be [`f32`], which is guaranteed to be an [IEEE 754 single-precision float] in Rust. That said, the standard technically only guarantees that it be a floating-point number, and it may have less precision than `f32` or not follow the IEEE-754 standard at all.
-[IEEE-754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
+[IEEE 754 single-precision float]: https://en.wikipedia.org/wiki/IEEE_754
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index 82e63a7fe..8923f548a 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -1,7 +1,6 @@
-use crate::ascii;
use crate::cmp::Ordering;
use crate::ffi::c_char;
-use crate::fmt::{self, Write};
+use crate::fmt;
use crate::intrinsics;
use crate::ops;
use crate::slice;
@@ -121,10 +120,10 @@ enum FromBytesWithNulErrorKind {
}
impl FromBytesWithNulError {
- fn interior_nul(pos: usize) -> FromBytesWithNulError {
+ const fn interior_nul(pos: usize) -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::InteriorNul(pos) }
}
- fn not_nul_terminated() -> FromBytesWithNulError {
+ const fn not_nul_terminated() -> FromBytesWithNulError {
FromBytesWithNulError { kind: FromBytesWithNulErrorKind::NotNulTerminated }
}
@@ -161,11 +160,7 @@ impl fmt::Display for FromBytesUntilNulError {
#[stable(feature = "cstr_debug", since = "1.3.0")]
impl fmt::Debug for CStr {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "\"")?;
- for byte in self.to_bytes().iter().flat_map(|&b| ascii::escape_default(b)) {
- f.write_char(byte as char)?;
- }
- write!(f, "\"")
+ write!(f, "\"{}\"", self.to_bytes().escape_ascii())
}
}
@@ -226,9 +221,7 @@ impl CStr {
/// # Examples
///
/// ```ignore (extern-declaration)
- /// # fn main() {
- /// use std::ffi::CStr;
- /// use std::os::raw::c_char;
+ /// use std::ffi::{c_char, CStr};
///
/// extern "C" {
/// fn my_string() -> *const c_char;
@@ -238,14 +231,26 @@ impl CStr {
/// let slice = CStr::from_ptr(my_string());
/// println!("string returned: {}", slice.to_str().unwrap());
/// }
- /// # }
+ /// ```
+ ///
+ /// ```
+ /// #![feature(const_cstr_methods)]
+ ///
+ /// use std::ffi::{c_char, CStr};
+ ///
+ /// const HELLO_PTR: *const c_char = {
+ /// const BYTES: &[u8] = b"Hello, world!\0";
+ /// BYTES.as_ptr().cast()
+ /// };
+ /// const HELLO: &CStr = unsafe { CStr::from_ptr(HELLO_PTR) };
/// ```
///
/// [valid]: core::ptr#safety
#[inline]
#[must_use]
#[stable(feature = "rust1", since = "1.0.0")]
- pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
// SAFETY: The caller has provided a pointer that points to a valid C
// string with a NUL terminator of size less than `isize::MAX`, whose
// content remain valid and doesn't change for the lifetime of the
@@ -257,13 +262,29 @@ impl CStr {
//
// The cast from c_char to u8 is ok because a c_char is always one byte.
unsafe {
- extern "C" {
- /// Provided by libc or compiler_builtins.
- fn strlen(s: *const c_char) -> usize;
+ const fn strlen_ct(s: *const c_char) -> usize {
+ let mut len = 0;
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ while unsafe { *s.add(len) } != 0 {
+ len += 1;
+ }
+
+ len
}
- let len = strlen(ptr);
- let ptr = ptr as *const u8;
- CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
+
+ fn strlen_rt(s: *const c_char) -> usize {
+ extern "C" {
+ /// Provided by libc or compiler_builtins.
+ fn strlen(s: *const c_char) -> usize;
+ }
+
+ // SAFETY: Outer caller has provided a pointer to a valid C string.
+ unsafe { strlen(s) }
+ }
+
+ let len = intrinsics::const_eval_select((ptr,), strlen_ct, strlen_rt);
+ Self::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr.cast(), len + 1))
}
}
@@ -299,7 +320,8 @@ impl CStr {
/// ```
///
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
- pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
+ #[rustc_const_unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
+ pub const fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) => {
@@ -348,7 +370,8 @@ impl CStr {
/// assert!(cstr.is_err());
/// ```
#[stable(feature = "cstr_from_bytes", since = "1.10.0")]
- pub fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, FromBytesWithNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) if nul_pos + 1 == bytes.len() => {
@@ -387,6 +410,7 @@ impl CStr {
#[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")]
#[rustc_allow_const_fn_unstable(const_eval_select)]
pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
+ #[inline]
fn rt_impl(bytes: &[u8]) -> &CStr {
// Chance at catching some UB at runtime with debug builds.
debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0);
@@ -476,6 +500,34 @@ impl CStr {
self.inner.as_ptr()
}
+ /// Returns `true` if `self.to_bytes()` has a length of 0.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(cstr_is_empty)]
+ ///
+ /// use std::ffi::CStr;
+ /// # use std::ffi::FromBytesWithNulError;
+ ///
+ /// # fn main() { test().unwrap(); }
+ /// # fn test() -> Result<(), FromBytesWithNulError> {
+ /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
+ /// assert!(!cstr.is_empty());
+ ///
+ /// let empty_cstr = CStr::from_bytes_with_nul(b"\0")?;
+ /// assert!(empty_cstr.is_empty());
+ /// # Ok(())
+ /// # }
+ /// ```
+ #[inline]
+ #[unstable(feature = "cstr_is_empty", issue = "102444")]
+ pub const fn is_empty(&self) -> bool {
+ // SAFETY: We know there is at least one byte; for empty strings it
+ // is the NUL terminator.
+ (unsafe { self.inner.get_unchecked(0) }) == &0
+ }
+
/// Converts this C string to a byte slice.
///
/// The returned slice will **not** contain the trailing nul terminator that this C
@@ -497,7 +549,8 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn to_bytes(&self) -> &[u8] {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn to_bytes(&self) -> &[u8] {
let bytes = self.to_bytes_with_nul();
// SAFETY: to_bytes_with_nul returns slice with length at least 1
unsafe { bytes.get_unchecked(..bytes.len() - 1) }
@@ -524,7 +577,8 @@ impl CStr {
#[must_use = "this returns the result of the operation, \
without modifying the original"]
#[stable(feature = "rust1", since = "1.0.0")]
- pub fn to_bytes_with_nul(&self) -> &[u8] {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn to_bytes_with_nul(&self) -> &[u8] {
// SAFETY: Transmuting a slice of `c_char`s to a slice of `u8`s
// is safe on all supported targets.
unsafe { &*(&self.inner as *const [c_char] as *const [u8]) }
@@ -547,7 +601,8 @@ impl CStr {
/// assert_eq!(cstr.to_str(), Ok("foo"));
/// ```
#[stable(feature = "cstr_to_str", since = "1.4.0")]
- pub fn to_str(&self) -> Result<&str, str::Utf8Error> {
+ #[rustc_const_unstable(feature = "const_cstr_methods", issue = "101719")]
+ pub const fn to_str(&self) -> Result<&str, 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