1use std::ffi::{CStr, CString};
18
19pub trait IntoCString {
21 fn into_c_string(self) -> CString;
23}
24
25impl IntoCString for CString {
26 fn into_c_string(self) -> Self {
27 self
28 }
29}
30
31impl IntoCString for &CStr {
32 fn into_c_string(self) -> CString {
33 self.to_owned()
34 }
35}
36
37impl IntoCString for String {
38 fn into_c_string(self) -> CString {
39 let s = if self.contains('\0') {
40 sanitize_nul(&self)
41 } else {
42 self
43 };
44 CString::new(s).unwrap()
45 }
46}
47
48impl IntoCString for &str {
49 fn into_c_string(self) -> CString {
50 if self.contains('\0') {
51 let s = sanitize_nul(self);
52 CString::new(s).unwrap()
53 } else {
54 CString::new(self).unwrap()
55 }
56 }
57}
58
59fn sanitize_nul(s: &str) -> String {
60 s.replace('\0', "\u{fffd}")
61}
62
63#[cfg(test)]
64mod tests {
65 use super::*;
66 use byte_strings::c_str;
67
68 #[test]
69 fn into_c_string_ok() {
70 assert_eq!("bonjour".into_c_string().as_ref(), c_str!("bonjour"));
71 assert_eq!("al\0ias\0".into_c_string().as_ref(), c_str!("al�ias�"));
72 assert_eq!(c_str!(b"ab\xefe").into_c_string().as_ref(), c_str!(b"ab\xefe"));
73 }
74}