use std::ffi::{CStr, CString};
pub trait IntoCString {
fn into_c_string(self) -> CString;
}
impl IntoCString for CString {
fn into_c_string(self) -> Self {
self
}
}
impl IntoCString for &CStr {
fn into_c_string(self) -> CString {
self.to_owned()
}
}
impl IntoCString for String {
fn into_c_string(self) -> CString {
let s = if self.contains('\0') {
sanitize_nul(&self)
} else {
self
};
CString::new(s).unwrap()
}
}
impl IntoCString for &str {
fn into_c_string(self) -> CString {
if self.contains('\0') {
let s = sanitize_nul(self);
CString::new(s).unwrap()
} else {
CString::new(self).unwrap()
}
}
}
fn sanitize_nul(s: &str) -> String {
s.replace('\0', "\u{fffd}")
}
#[cfg(test)]
mod tests {
use super::*;
use byte_strings::c_str;
#[test]
fn into_c_string_ok() {
assert_eq!("bonjour".into_c_string().as_ref(), c_str!("bonjour"));
assert_eq!("al\0ias\0".into_c_string().as_ref(), c_str!("al�ias�"));
assert_eq!(c_str!(b"ab\xefe").into_c_string().as_ref(), c_str!(b"ab\xefe"));
}
}