use std::os::raw::c_char;
use std::ffi::CStr;
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct ConstCStr {
pub val: &'static str,
}
impl ConstCStr {
pub fn to_str(&self) -> &'static str {
&self.val[..self.val.len() - 1]
}
pub fn to_bytes(&self) -> &'static [u8] {
self.to_str().as_bytes()
}
pub fn to_bytes_with_nul(&self) -> &'static [u8] {
self.val.as_bytes()
}
pub fn as_ptr(&self) -> *const c_char {
let bytes = self.val.as_bytes();
assert_eq!(bytes[bytes.len() - 1], b'\0');
self.val.as_bytes().as_ptr() as *const c_char
}
pub fn as_cstr(&self) -> &'static CStr {
let bytes = self.val.as_bytes();
assert_eq!(bytes[bytes.len() - 1], b'\0');
unsafe {
CStr::from_bytes_with_nul_unchecked(bytes)
}
}
}
#[macro_export]
macro_rules! const_cstr {
($(pub $strname:ident = $strval:expr);+;) => (
$(
pub const $strname: $crate::ConstCStr = const_cstr!($strval);
)+
);
($strval:expr) => (
$crate::ConstCStr { val: concat!($strval, "\0") }
);
($($strname:ident = $strval:expr);+;) => (
$(
const $strname: $crate::ConstCStr = const_cstr!($strval);
)+
);
}
#[test]
fn test_creates_valid_str() {
const_cstr! {
HELLO_CSTR = "Hello, world!";
}
let cstr = unsafe { CStr::from_ptr(HELLO_CSTR.as_ptr()) };
assert_eq!(HELLO_CSTR.to_str(), cstr.to_str().unwrap());
}
#[cfg(test)]
mod test_creates_pub_str_mod {
const_cstr! {
pub FIRST = "first";
pub SECOND = "second";
}
}
#[test]
fn test_creates_pub_str() {
assert_eq!(test_creates_pub_str_mod::FIRST.to_str(), "first");
assert_eq!(test_creates_pub_str_mod::SECOND.to_str(), "second");
}