pub struct CStrArray<const N: usize> {
pub data: [NonZeroU8; N],
/* private fields */
}Expand description
Fixed-size CStr, backed by an array.
The length N is the number of bytes in the string not including the nul terminator.
Because it has a fixed size, it can be put directly in a static and all
casting operations are constant-time.
§Examples
Small C strings of fixed size:
let mut airports = [
cstr_array!("JFK"), cstr_array!("LAX"),
cstr_array!("LHR"), cstr_array!("CDG"),
cstr_array!("HND"), cstr_array!("PEK"),
cstr_array!("DXB"), cstr_array!("AMS"),
cstr_array!("FRA"), cstr_array!("SIN"),
];
// All of the C strings are contiguous in memory.
assert_eq!(core::mem::size_of_val(&airports), 40);
airports.sort();
assert_eq!(airports[0], c"AMS");Storing CStr contents directly in a static:
cstr_array! {
static FOO = b"Hello, world!";
static mut FOO_MUT = c"c string buffer";
}
assert_eq!(&FOO, c"Hello, world!");
assert_eq!(size_of_val(&FOO), 14);
let foo_mut = unsafe { &mut *&raw mut FOO_MUT };
foo_mut.data[0] = b'C'.try_into().unwrap();
assert_eq!(foo_mut, c"C string buffer");
assert_eq!(size_of_val(foo_mut), 16);Fields§
§data: [NonZeroU8; N]The non-nul data in this C string.
Implementations§
Source§impl<const N: usize> CStrArray<N>
impl<const N: usize> CStrArray<N>
Sourcepub const fn new(val: &CStr) -> Result<Self, CStrLenError<N>>
pub const fn new(val: &CStr) -> Result<Self, CStrLenError<N>>
Builds a StrArray<N> from val.
This returns an Err if val.len() != N.
If val is a literal or const, consider using cstr_array!
instead, which always builds a CStrArray with the correct N
by checking the length at compile time.
§Examples
let cstring = CString::new(format!("he{}", "llo")).unwrap();
let s = CStrArray::<5>::new(&cstring).unwrap();
assert_eq!(s, c"hello");
assert!(CStrArray::<5>::new(c"foo").is_err());Sourcepub const unsafe fn new_unchecked(val: &CStr) -> Self
pub const unsafe fn new_unchecked(val: &CStr) -> Self
Sourcepub const fn ref_from_c_str(val: &CStr) -> Result<&Self, CStrLenError<N>>
pub const fn ref_from_c_str(val: &CStr) -> Result<&Self, CStrLenError<N>>
Converts a &CStr to a &CStrArray<N> with a length check.
§Examples
let s: &CStrArray<5> = CStrArray::ref_from_c_str(c"hello").unwrap();
assert_eq!(s, c"hello");
assert!(CStrArray::<5>::ref_from_c_str(c"foo").is_err());Sourcepub const unsafe fn ref_from_c_str_unchecked(val: &CStr) -> &Self
pub const unsafe fn ref_from_c_str_unchecked(val: &CStr) -> &Self
Sourcepub const fn mut_from_c_str(
val: &mut CStr,
) -> Result<&mut Self, CStrLenError<N>>
pub const fn mut_from_c_str( val: &mut CStr, ) -> Result<&mut Self, CStrLenError<N>>
Converts a &mut CStr to a &mut CStrArray<N> with a length check.
§Examples
let mut boxed = CString::new("hello").unwrap().into_boxed_c_str();
let s_mut = CStrArray::<5>::mut_from_c_str(&mut boxed).unwrap();
s_mut.data[0] = b'H'.try_into().unwrap();
assert_eq!(&*boxed, c"Hello");
let mut short = CString::new("foo").unwrap().into_boxed_c_str();
assert!(CStrArray::<5>::mut_from_c_str(&mut short).is_err());§const support
This function is const if &mut is supported in const.
Sourcepub const unsafe fn mut_from_c_str_unchecked(val: &mut CStr) -> &mut Self
pub const unsafe fn mut_from_c_str_unchecked(val: &mut CStr) -> &mut Self
Converts a &mut CStr to a &mut CStrArray<N> without a length check.
§Examples
let mut boxed = CString::new("abc").unwrap().into_boxed_c_str();
// SAFETY: boxed.count_bytes() == 3
let m: &mut CStrArray<3> = unsafe {
CStrArray::mut_from_c_str_unchecked(&mut boxed)
};
m.data[0] = b'A'.try_into().unwrap();
assert_eq!(&*boxed, c"Abc");§Safety
val.count_bytes() == N or else behavior is undefined.
§const support
This function is const if &mut is supported in const.
Sourcepub const fn from_bytes_without_nul(
bytes: &[u8; N],
) -> Result<Self, InteriorNulError>
pub const fn from_bytes_without_nul( bytes: &[u8; N], ) -> Result<Self, InteriorNulError>
Constructs a CStrArray<N> from an array with its byte contents.
Note that bytes should not include the nul terminator -
it is appended automatically by this method.
If val is a literal or const, consider using cstr_array!
instead, which checks for the presence of a nul at compile time.
§Examples
let s = CStrArray::from_bytes_without_nul(b"hello").unwrap();
assert_eq!(s, c"hello");
let bytes_with_nul = b"he\0lo";
assert!(CStrArray::from_bytes_without_nul(bytes_with_nul).is_err());Sourcepub const unsafe fn from_bytes_without_nul_unchecked(bytes: &[u8; N]) -> Self
pub const unsafe fn from_bytes_without_nul_unchecked(bytes: &[u8; N]) -> Self
Constructs a CStrArray<N> from an array with its byte contents and no checks.
Note that this does not include the nul terminator - it is appended automatically.
§Examples
// SAFETY: b"hello" contains no nul bytes
let s = unsafe { CStrArray::from_bytes_without_nul_unchecked(b"hello") };
assert_eq!(s, c"hello");§Safety
bytes must not have any 0 (nul) bytes.
Sourcepub const fn as_c_str(&self) -> &CStr
pub const fn as_c_str(&self) -> &CStr
Borrows this CStrArray as a &CStr.
This is called by Deref automatically.
§Examples
let s = cstr_array!(c"hello");
assert_eq!(s.as_c_str().to_str().unwrap(), "hello");
assert_eq!(s.to_str().unwrap(), "hello"); // using derefSourcepub const fn as_mut_c_str(&mut self) -> &mut CStr
pub const fn as_mut_c_str(&mut self) -> &mut CStr
Borrows this CStrArray as a &mut CStr.
This is called by DerefMut automatically.
While &mut CStr is currently undersupported in the standard library,
it can be safely constructed by borrowing a Box<CStr> and unsafe code
can utilize its invariants.
§Examples
fn make_c_str_ascii_uppercase(x: &mut CStr) {
let mut p: *mut u8 = ptr::from_mut(x).cast();
loop {
// SAFETY: the last byte of `CStr` is 0
let b = unsafe { &mut *p };
match *b {
0 => return,
b'a'..=b'z' => *b -= 32,
_ => {}
}
// SAFETY: the end of the `CStr` has not been reached
p = unsafe { p.add(1) };
}
}
let mut s = cstr_array!(c"hello");
make_c_str_ascii_uppercase(s.as_mut_c_str()); // or just `&mut s`
assert_eq!(s, c"HELLO");§const support
This function is const if &mut is supported in const.
Sourcepub const fn as_bytes(&self) -> &[u8; N]
pub const fn as_bytes(&self) -> &[u8; N]
Converts this C string to a byte array reference.
The returned slice will not contain the trailing nul terminator that this C string has.
§Examples
let x = cstr_array!(c"Hello");
let &[a, b @ .., c] = x.as_bytes();
assert_eq!(a, b'H');
assert_eq!(b, *b"ell");
assert_eq!(c, b'o');Sourcepub const fn as_nonzero_bytes(&self) -> &[NonZeroU8; N]
pub const fn as_nonzero_bytes(&self) -> &[NonZeroU8; N]
Converts this C string to a &[NonZero<u8>].
This is also exposed in self.data.
§Examples
let s = cstr_array!(c"hello");
let bytes = s.as_nonzero_bytes();
assert_eq!(bytes.len(), 5);
assert_eq!(bytes[0].get(), b'h');Sourcepub const fn as_mut_nonzero_bytes(&mut self) -> &mut [NonZeroU8; N]
pub const fn as_mut_nonzero_bytes(&mut self) -> &mut [NonZeroU8; N]
Converts this C string to a &mut [NonZero<u8>].
This allows for safe in-place mutation of the C string contents without changing its length.
This is also exposed in self.data.
§Examples
let mut s = cstr_array!(c"hello");
s.as_mut_nonzero_bytes()[0] = b'H'.try_into().unwrap();
assert_eq!(s, c"Hello");§const support
This function is const if &mut is supported in const.
Sourcepub const fn as_bytes_with_nul(&self) -> &[u8] ⓘ
pub const fn as_bytes_with_nul(&self) -> &[u8] ⓘ
Converts this C string to a byte slice containing the trailing 0 byte.
The length of the slice is N + 1.
§Examples
let s = cstr_array!(c"hello");
assert_eq!(s.as_bytes_with_nul(), b"hello\0");
assert_eq!(s.as_bytes_with_nul().len(), 6);Sourcepub const fn as_mut_ptr(&mut self) -> *mut c_char
pub const fn as_mut_ptr(&mut self) -> *mut c_char
Returns the mutable inner pointer to this C string.
The returned pointer will be valid for as long as self is,
and points to a contiguous region of memory terminated with
a 0 byte to represent the end of the string.
The type of the returned pointer is *mut c_char, and whether
it’s an alias for *mut i8 or *mut u8 is platform-specific.
WARNING
The returned pointer can be mutated through, but certain constraints must be upheld:
- It is your responsibility to make sure that the underlying memory is not freed too early.
- The nul terminator cannot be relocated to earlier in the string.
In other words, the length of the C string cannot be changed.
This restriction can never be loosened, as the first
Nbytes ofselfare required to have non-zero contents.
§Examples
let mut s = cstr_array!("hello");
unsafe { s.as_mut_ptr().cast::<u8>().write(b'J') }
assert_eq!(s, c"Jello");§const support
This function is const if &mut is supported in const.
Sourcepub const fn into_bytes(self) -> [u8; N]
pub const fn into_bytes(self) -> [u8; N]
Consumes self into its underlying array.
§Examples
let x = cstr_array!(c"Fizzy");
let [a, b @ .., c] = x.into_bytes();
assert_eq!(a, b'F');
assert_eq!(b, *b"izz");
assert_eq!(c, b'y');Sourcepub const fn count_bytes(&self) -> usize
👎Deprecated: use len
pub const fn count_bytes(&self) -> usize
lenReturns the fixed length.
This uses the same name as CStr::count_bytes to prevent
it from being called with Deref.
Sourcepub const fn to_bytes(&self) -> &[u8] ⓘ
👎Deprecated: use as_bytes
pub const fn to_bytes(&self) -> &[u8] ⓘ
as_bytesConverts this C string to a byte slice.
This uses the same name as CStr::to_bytes to prevent
it from being called with Deref.
Sourcepub const fn to_bytes_with_nul(&self) -> &[u8] ⓘ
👎Deprecated: use as_bytes_with_nul
pub const fn to_bytes_with_nul(&self) -> &[u8] ⓘ
as_bytes_with_nulConverts this C string to a byte slice.
This uses the same name as CStr::to_bytes_with_nul to prevent
it from being called with Deref.
Methods from Deref<Target = CStr>§
1.0.0 · Sourcepub fn as_ptr(&self) -> *const i8
pub fn as_ptr(&self) -> *const i8
Returns the inner pointer to this C string.
The returned pointer will be valid for as long as self is, and points
to a contiguous region of memory terminated with a 0 byte to represent
the end of the string.
The type of the returned pointer is
*const c_char, and whether it’s
an alias for *const i8 or *const u8 is platform-specific.
WARNING
The returned pointer is read-only; writing to it (including passing it to C code that writes to it) causes undefined behavior.
It is your responsibility to make sure that the underlying memory is not
freed too early. For example, the following code will cause undefined
behavior when ptr is used inside the unsafe block:
use std::ffi::{CStr, CString};
// 💀 The meaning of this entire program is undefined,
// 💀 and nothing about its behavior is guaranteed,
// 💀 not even that its behavior resembles the code as written,
// 💀 just because it contains a single instance of undefined behavior!
// 🚨 creates a dangling pointer to a temporary `CString`
// 🚨 that is deallocated at the end of the statement
let ptr = CString::new("Hi!".to_uppercase()).unwrap().as_ptr();
// without undefined behavior, you would expect that `ptr` equals:
dbg!(CStr::from_bytes_with_nul(b"HI!\0").unwrap());
// 🙏 Possibly the program behaved as expected so far,
// 🙏 and this just shows `ptr` is now garbage..., but
// 💀 this violates `CStr::from_ptr`'s safety contract
// 💀 leading to a dereference of a dangling pointer,
// 💀 which is immediate undefined behavior.
// 💀 *BOOM*, you're dead, your entire program has no meaning.
dbg!(unsafe { CStr::from_ptr(ptr) });This happens because, the pointer returned by as_ptr does not carry any
lifetime information, and the CString is deallocated immediately after
the expression that it is part of has been evaluated.
To fix the problem, bind the CString to a local variable:
use std::ffi::{CStr, CString};
let c_str = CString::new("Hi!".to_uppercase()).unwrap();
let ptr = c_str.as_ptr();
assert_eq!(unsafe { CStr::from_ptr(ptr) }, c"HI!");1.79.0 · Sourcepub fn count_bytes(&self) -> usize
pub fn count_bytes(&self) -> usize
Returns the length of self. Like C’s strlen, this does not include the nul terminator.
Note: This method is currently implemented as a constant-time cast, but it is planned to alter its definition in the future to perform the length calculation whenever this method is called.
§Examples
assert_eq!(c"foo".count_bytes(), 3);
assert_eq!(c"".count_bytes(), 0);1.71.0 · Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Returns true if self.to_bytes() has a length of 0.
§Examples
assert!(!c"foo".is_empty());
assert!(c"".is_empty());1.0.0 · Sourcepub fn to_bytes(&self) -> &[u8] ⓘ
pub fn to_bytes(&self) -> &[u8] ⓘ
Converts this C string to a byte slice.
The returned slice will not contain the trailing nul terminator that this C string has.
Note: This method is currently implemented as a constant-time cast, but it is planned to alter its definition in the future to perform the length calculation whenever this method is called.
§Examples
assert_eq!(c"foo".to_bytes(), b"foo");1.0.0 · Sourcepub fn to_bytes_with_nul(&self) -> &[u8] ⓘ
pub fn to_bytes_with_nul(&self) -> &[u8] ⓘ
Converts this C string to a byte slice containing the trailing 0 byte.
This function is the equivalent of CStr::to_bytes except that it
will retain the trailing nul terminator instead of chopping it off.
Note: This method is currently implemented as a 0-cost cast, but it is planned to alter its definition in the future to perform the length calculation whenever this method is called.
§Examples
assert_eq!(c"foo".to_bytes_with_nul(), b"foo\0");Sourcepub fn bytes(&self) -> Bytes<'_>
🔬This is a nightly-only experimental API. (cstr_bytes)
pub fn bytes(&self) -> Bytes<'_>
cstr_bytes)Iterates over the bytes in this C string.
The returned iterator will not contain the trailing nul terminator that this C string has.
§Examples
#![feature(cstr_bytes)]
assert!(c"foo".bytes().eq(*b"foo"));Sourcepub fn display(&self) -> impl Display
🔬This is a nightly-only experimental API. (cstr_display)
pub fn display(&self) -> impl Display
cstr_display)Returns an object that implements Display for safely printing a CStr that may
contain non-Unicode data.
Behaves as if self were first lossily converted to a str, with invalid UTF-8 presented
as the Unicode replacement character: �.
§Examples
#![feature(cstr_display)]
let cstr = c"Hello, world!";
println!("{}", cstr.display());1.4.0 · Sourcepub fn to_string_lossy(&self) -> Cow<'_, str>
pub fn to_string_lossy(&self) -> Cow<'_, str>
Converts a CStr into a Cow<str>.
If the contents of the CStr are valid UTF-8 data, this
function will return a Cow::Borrowed(&str)
with the corresponding &str slice. Otherwise, it will
replace any invalid UTF-8 sequences with
U+FFFD REPLACEMENT CHARACTER and return a
Cow::Owned(String) with the result.
§Examples
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;
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;
assert_eq!(
c"Hello \xF0\x90\x80World".to_string_lossy(),
Cow::Owned(String::from("Hello �World")) as Cow<'_, str>
);