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