summaryrefslogtreecommitdiffstats
path: root/vendor/rustix/src/cstr.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/rustix/src/cstr.rs')
-rw-r--r--vendor/rustix/src/cstr.rs76
1 files changed, 76 insertions, 0 deletions
diff --git a/vendor/rustix/src/cstr.rs b/vendor/rustix/src/cstr.rs
new file mode 100644
index 000000000..5e3364380
--- /dev/null
+++ b/vendor/rustix/src/cstr.rs
@@ -0,0 +1,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
+///
+/// ```rust,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");
+}