stringer/
lib.rs

1use std::ffi::{CStr, CString, NulError};
2use std::os::raw::c_char;
3use std::str::Utf8Error;
4
5pub fn string_to_cstring(string: String) -> Result<CString, NulError> {
6    let result = CString::new(string)?;
7
8    Ok(result)
9}
10
11pub fn cstr_to_string(unsafe_string: *const c_char) -> Result<String, Utf8Error> {
12    let result = unsafe { CStr::from_ptr(unsafe_string) }
13        .to_str()?
14        .to_string();
15
16    Ok(result)
17}
18
19#[cfg(test)]
20mod tests {
21    use super::*;
22    use std::ffi::CString;
23
24    #[test]
25    fn roundtrip_ascii() {
26        let original = String::from("Hello, world!");
27        let cstring = string_to_cstring(original.clone()).unwrap();
28
29        let ptr = cstring.as_ptr();
30        let recovered = cstr_to_string(ptr).unwrap();
31
32        assert_eq!(recovered, original);
33    }
34
35    #[test]
36    fn roundtrip_unicode() {
37        let original = String::from("こんにちは世界");
38        let cstring = string_to_cstring(original.clone()).unwrap();
39
40        let ptr = cstring.as_ptr();
41        let recovered = cstr_to_string(ptr).unwrap();
42
43        assert_eq!(recovered, original);
44    }
45
46    #[test]
47    fn empty_string() {
48        let original = String::new();
49        let cstring = string_to_cstring(original.clone()).unwrap();
50
51        let ptr = cstring.as_ptr();
52        let recovered = cstr_to_string(ptr).unwrap();
53
54        assert_eq!(recovered, original);
55    }
56
57    #[test]
58    fn from_cstring_direct() {
59        let original = "Direct CString".to_string();
60        let cstring = CString::new(original.clone()).unwrap();
61
62        let ptr = cstring.as_ptr();
63        let recovered = cstr_to_string(ptr).unwrap();
64
65        assert_eq!(recovered, original);
66    }
67
68    #[test]
69    fn invalid_utf8_pointer() {
70        let bytes: &[u8] = b"\xff\x00";
71        let ptr = bytes.as_ptr() as *const c_char;
72
73        assert!(cstr_to_string(ptr).is_err());
74    }
75
76    #[test]
77    fn interior_null_byte() {
78        let original = String::from("Hello\0World");
79
80        assert!(string_to_cstring(original).is_err());
81    }
82
83    #[test]
84    fn invalid_utf8_sequence_in_cstr_to_string() {
85        let bytes: &[u8] = b"\xff\x00";
86        let ptr = bytes.as_ptr() as *const c_char;
87
88        assert!(cstr_to_string(ptr).is_err());
89    }
90}