use std::ffi::CStr;
use std::os::raw::c_char;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum CstrError {
#[error("null pointer")]
NullPointer,
#[error("invalid UTF-8: {0}")]
InvalidUtf8(#[from] std::str::Utf8Error),
}
pub fn cstr_to_string(ptr: *const c_char) -> Result<String, CstrError> {
if ptr.is_null() {
return Err(CstrError::NullPointer);
}
let s = unsafe { CStr::from_ptr(ptr) };
s.to_str().map(|s| s.to_string()).map_err(CstrError::from)
}
#[cfg_attr(coverage_nightly, coverage(off))]
#[cfg(test)]
mod tests {
use super::*;
use std::ffi::CString;
#[test]
fn test_cstr_to_string_valid() {
let s = CString::new("hello").unwrap();
let result = cstr_to_string(s.as_ptr()).unwrap();
assert_eq!(result, "hello".to_string());
}
#[test]
fn test_cstr_to_string_null() {
let result = cstr_to_string(std::ptr::null());
assert!(result.is_err());
assert!(matches!(result.unwrap_err(), CstrError::NullPointer));
}
#[test]
fn test_cstr_to_string_empty() {
let s = CString::new("").unwrap();
let result = cstr_to_string(s.as_ptr()).unwrap();
assert_eq!(result, "");
}
#[test]
fn test_cstr_to_string_invalid_utf8() {
let invalid_bytes: &[u8] = b"\xff\xfe\0";
let cstr = unsafe { CStr::from_bytes_with_nul_unchecked(invalid_bytes) };
let result = cstr.to_str();
assert!(result.is_err());
let err = result.unwrap_err();
let e = CstrError::InvalidUtf8(err);
assert!(e.to_string().contains("invalid UTF-8"));
}
#[test]
fn test_cstr_error_null_pointer_display() {
let err = CstrError::NullPointer;
assert_eq!(err.to_string(), "null pointer");
}
}