1 // Copyright 2024 Red Hat, Inc. 2 // Author(s): Paolo Bonzini <pbonzini@redhat.com> 3 // SPDX-License-Identifier: GPL-2.0-or-later 4 5 #![doc(hidden)] 6 //! This module provides a macro to define a constant of type 7 //! [`CStr`](std::ffi::CStr), for compatibility with versions of 8 //! Rust that lack `c""` literals. 9 //! 10 //! Documentation is hidden because it only exposes macros, which 11 //! are exported directly from `qemu_api`. 12 13 #[macro_export] 14 /// Given a string constant _without_ embedded or trailing NULs, return 15 /// a `CStr`. 16 /// 17 /// Needed for compatibility with Rust <1.77. 18 macro_rules! c_str { 19 ($str:expr) => {{ 20 const STRING: &str = concat!($str, "\0"); 21 const BYTES: &[u8] = STRING.as_bytes(); 22 23 // "for" is not allowed in const context... oh well, 24 // everybody loves some lisp. This could be turned into 25 // a procedural macro if this is a problem; alternatively 26 // Rust 1.72 makes CStr::from_bytes_with_nul a const function. 27 const fn f(b: &[u8], i: usize) { 28 if i == b.len() - 1 { 29 } else if b[i] == 0 { 30 panic!("c_str argument contains NUL") 31 } else { 32 f(b, i + 1) 33 } 34 } 35 f(BYTES, 0); 36 37 // SAFETY: absence of NULs apart from the final byte was checked above 38 unsafe { std::ffi::CStr::from_bytes_with_nul_unchecked(BYTES) } 39 }}; 40 } 41 42 #[cfg(test)] 43 mod tests { 44 use std::ffi::CStr; 45 46 use crate::c_str; 47 48 #[test] test_cstr_macro()49 fn test_cstr_macro() { 50 let good = c_str!(""); 51 let good_bytes = b"\xf0\x9f\xa6\x80\0"; 52 assert_eq!(good.to_bytes_with_nul(), good_bytes); 53 } 54 55 #[test] test_cstr_macro_const()56 fn test_cstr_macro_const() { 57 const GOOD: &CStr = c_str!(""); 58 const GOOD_BYTES: &[u8] = b"\xf0\x9f\xa6\x80\0"; 59 assert_eq!(GOOD.to_bytes_with_nul(), GOOD_BYTES); 60 } 61 } 62