1 /// A macro for [`CStr`] literals.
2 ///
3 /// This can make passing string literals to rustix APIs more efficient, since
4 /// most underlying system calls with string arguments expect NUL-terminated
5 /// strings, and passing strings to rustix as `CStr`s means that rustix doesn't
6 /// need to copy them into a separate buffer to NUL-terminate them.
7 ///
8 /// [`CStr`]: crate::ffi::CStr
9 ///
10 /// # Examples
11 ///
12 /// ```rust,no_run
13 /// # #[cfg(feature = "fs")]
14 /// # fn main() -> rustix::io::Result<()> {
15 /// use rustix::cstr;
16 /// use rustix::fs::{cwd, statat, AtFlags};
17 ///
18 /// let metadata = statat(cwd(), cstr!("test.txt"), AtFlags::empty())?;
19 /// # Ok(())
20 /// # }
21 /// # #[cfg(not(feature = "fs"))]
22 /// # fn main() {}
23 /// ```
24 #[allow(unused_macros)]
25 #[macro_export]
26 macro_rules! cstr {
27 ($str:literal) => {{
28 // Check for NUL manually, to ensure safety.
29 //
30 // In release builds, with strings that don't contain NULs, this
31 // constant-folds away.
32 //
33 // We don't use std's `CStr::from_bytes_with_nul`; as of this writing,
34 // that function isn't defined as `#[inline]` in std and doesn't
35 // constant-fold away.
36 assert!(
37 !$str.bytes().any(|b| b == b'\0'),
38 "cstr argument contains embedded NUL bytes",
39 );
40
41 #[allow(unsafe_code, unused_unsafe)]
42 {
43 // Now that we know the string doesn't have embedded NULs, we can call
44 // `from_bytes_with_nul_unchecked`, which as of this writing is defined
45 // as `#[inline]` and completely optimizes away.
46 //
47 // Safety: We have manually checked that the string does not contain
48 // embedded NULs above, and we append or own NUL terminator here.
49 unsafe {
50 $crate::ffi::CStr::from_bytes_with_nul_unchecked(concat!($str, "\0").as_bytes())
51 }
52 }
53 }};
54 }
55
56 #[test]
test_cstr()57 fn test_cstr() {
58 use crate::ffi::CString;
59 use alloc::borrow::ToOwned;
60 assert_eq!(cstr!(""), &*CString::new("").unwrap());
61 assert_eq!(cstr!("").to_owned(), CString::new("").unwrap());
62 assert_eq!(cstr!("hello"), &*CString::new("hello").unwrap());
63 assert_eq!(cstr!("hello").to_owned(), CString::new("hello").unwrap());
64 }
65
66 #[test]
67 #[should_panic]
test_invalid_cstr()68 fn test_invalid_cstr() {
69 let _ = cstr!("hello\0world");
70 }
71
72 #[test]
73 #[should_panic]
test_invalid_empty_cstr()74 fn test_invalid_empty_cstr() {
75 let _ = cstr!("\0");
76 }
77