1use std::{ffi::CStr, fmt};
6
7use crate::sys;
8
9pub type Result<T> = std::result::Result<T, Error>;
11
12#[derive(Debug)]
14pub enum Error {
15 Unknown(String),
17
18 Overflow,
20
21 KeyNotFound(String),
23
24 IndexOutOfBounds {
26 index: usize,
28 length: usize,
30 },
31
32 EvalError(String),
34
35 InvalidType {
37 expected: &'static str,
39 actual: String,
41 },
42 NullPointer,
44
45 StringConversion(std::ffi::NulError),
47}
48
49impl fmt::Display for Error {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 Error::Unknown(msg) => write!(f, "Unknown error: {msg}"),
53 Error::Overflow => write!(f, "Overflow error"),
54 Error::KeyNotFound(key) => write!(f, "Key not found: {key}"),
55 Error::IndexOutOfBounds { index, length } => {
56 write!(f, "Index out of bounds: index {index}, length {length}")
57 },
58 Error::EvalError(msg) => write!(f, "Evaluation error: {msg}"),
59 Error::InvalidType { expected, actual } => {
60 write!(f, "Invalid type: expected {expected}, got {actual}")
61 },
62 Error::NullPointer => write!(f, "Null pointer error"),
63 Error::StringConversion(e) => write!(f, "String conversion error: {e}"),
64 }
65 }
66}
67
68impl std::error::Error for Error {}
69
70impl From<std::ffi::NulError> for Error {
71 fn from(e: std::ffi::NulError) -> Self {
72 Error::StringConversion(e)
73 }
74}
75
76#[cfg(feature = "store")]
85pub(crate) unsafe fn string_from_callback<F>(call: F) -> Option<String>
86where
87 F: FnOnce(sys::nix_get_string_callback, *mut std::os::raw::c_void),
88{
89 unsafe extern "C" fn collect(
90 start: *const std::os::raw::c_char,
91 n: std::os::raw::c_uint,
92 user_data: *mut std::os::raw::c_void,
93 ) {
94 let result = unsafe { &mut *(user_data as *mut Option<String>) };
95 if !start.is_null() {
96 let bytes =
97 unsafe { std::slice::from_raw_parts(start.cast::<u8>(), n as usize) };
98 *result = std::str::from_utf8(bytes).ok().map(|s| s.to_owned());
99 }
100 }
101
102 let mut result: Option<String> = None;
103 let user_data = &mut result as *mut _ as *mut std::os::raw::c_void;
104 call(Some(collect), user_data);
105 result
106}
107
108#[cfg(feature = "store")]
111pub(crate) fn check_err(
112 ctx: *mut sys::nix_c_context,
113 err: sys::nix_err,
114) -> Result<()> {
115 if err == sys::nix_err_NIX_OK {
116 return Ok(());
117 }
118
119 let msg = unsafe {
123 let ptr = sys::nix_err_msg(std::ptr::null_mut(), ctx, std::ptr::null_mut());
124 if ptr.is_null() {
125 None
126 } else {
127 Some(CStr::from_ptr(ptr).to_string_lossy().into_owned())
128 }
129 };
130
131 let detail = if err == sys::nix_err_NIX_ERR_NIX_ERROR {
133 unsafe {
134 string_from_callback(|cb, ud| {
135 sys::nix_err_info_msg(std::ptr::null_mut(), ctx, cb, ud);
136 })
137 }
138 } else {
139 None
140 };
141
142 let name = unsafe {
146 string_from_callback(|cb, ud| {
147 sys::nix_err_name(std::ptr::null_mut(), ctx, cb, ud);
148 })
149 };
150
151 let base_message = detail
152 .or(msg)
153 .unwrap_or_else(|| format!("Nix error code: {err}"));
154 let message = match name {
155 Some(n) if !n.is_empty() => format!("[{n}] {base_message}"),
156 _ => base_message,
157 };
158
159 match err {
160 sys::nix_err_NIX_ERR_UNKNOWN => Err(Error::Unknown(message)),
161 sys::nix_err_NIX_ERR_OVERFLOW => Err(Error::Overflow),
162 sys::nix_err_NIX_ERR_KEY => Err(Error::KeyNotFound(message)),
163 sys::nix_err_NIX_ERR_NIX_ERROR => Err(Error::EvalError(message)),
164 _ => Err(Error::Unknown(message)),
165 }
166}