use std::{error, fmt, os::raw::c_int};
use crate::helper::chars_to_string;
pub type Result<T> = std::result::Result<T, Error>;
pub const GP_OK: c_int = libgphoto2_sys::GP_OK as c_int;
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub enum ErrorKind {
Other,
BadParameters,
CameraBusy,
CameraError,
CorruptedData,
DirectoryExists,
DirectoryNotFound,
FileExists,
FileNotFound,
FixedLimitExceeded,
ModelNotFound,
NotSupported,
NoMemory,
NoSpace,
Io,
OsFailure,
PathNotAbsolute,
Timeout,
UnknownPort,
}
#[derive(PartialEq, Eq)]
pub struct Error {
error: c_int,
info: Option<String>,
}
impl Error {
pub fn new(error: c_int) -> Self {
Self { error, info: None }
}
pub fn kind(&self) -> ErrorKind {
match self.error {
libgphoto2_sys::GP_ERROR_BAD_PARAMETERS => ErrorKind::BadParameters,
libgphoto2_sys::GP_ERROR_CAMERA_BUSY => ErrorKind::CameraBusy,
libgphoto2_sys::GP_ERROR_CAMERA_ERROR => ErrorKind::CameraError,
libgphoto2_sys::GP_ERROR_CORRUPTED_DATA => ErrorKind::CorruptedData,
libgphoto2_sys::GP_ERROR_DIRECTORY_EXISTS => ErrorKind::DirectoryExists,
libgphoto2_sys::GP_ERROR_DIRECTORY_NOT_FOUND => ErrorKind::DirectoryNotFound,
libgphoto2_sys::GP_ERROR_FILE_EXISTS => ErrorKind::FileExists,
libgphoto2_sys::GP_ERROR_FILE_NOT_FOUND => ErrorKind::FileNotFound,
libgphoto2_sys::GP_ERROR_FIXED_LIMIT_EXCEEDED => ErrorKind::FixedLimitExceeded,
libgphoto2_sys::GP_ERROR_MODEL_NOT_FOUND => ErrorKind::ModelNotFound,
libgphoto2_sys::GP_ERROR_NOT_SUPPORTED => ErrorKind::NotSupported,
libgphoto2_sys::GP_ERROR_NO_MEMORY => ErrorKind::NoMemory,
libgphoto2_sys::GP_ERROR_NO_SPACE => ErrorKind::NoSpace,
libgphoto2_sys::GP_ERROR_IO => ErrorKind::Io,
libgphoto2_sys::GP_ERROR_OS_FAILURE => ErrorKind::OsFailure,
libgphoto2_sys::GP_ERROR_PATH_NOT_ABSOLUTE => ErrorKind::PathNotAbsolute,
libgphoto2_sys::GP_ERROR_TIMEOUT => ErrorKind::Timeout,
libgphoto2_sys::GP_ERROR_UNKNOWN_PORT => ErrorKind::UnknownPort,
libgphoto2_sys::GP_ERROR => ErrorKind::Other,
_ => ErrorKind::Other,
}
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Self {
Self { error: libgphoto2_sys::GP_ERROR_IO, info: Some(err.to_string()) }
}
}
impl From<std::ffi::NulError> for Error {
fn from(_: std::ffi::NulError) -> Self {
Self { error: libgphoto2_sys::GP_ERROR, info: Some("FFI: NulError".to_string()) }
}
}
impl From<&str> for Error {
fn from(message: &str) -> Self {
Self { error: libgphoto2_sys::GP_ERROR, info: Some(message.into()) }
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(unsafe { &chars_to_string(libgphoto2_sys::gp_result_as_string(self.error)) })?;
if let Some(error_info) = &self.info {
f.write_fmt(format_args!(" [{}]", error_info))?;
}
Ok(())
}
}
impl fmt::Debug for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::Display>::fmt(self, f)
}
}
impl error::Error for Error {}
#[macro_export]
macro_rules! try_gp_internal {
(@ $status:tt [ $($out:ident)* ] $func:ident ( $($args:tt)* ) &out $new_out:ident $($rest:tt)*) => {
try_gp_internal!(@ $status [ $($out)* $new_out ] $func ( $($args)* $new_out.as_mut_ptr() ) $($rest)*)
};
(@ $status:tt $out:tt $func:ident ( $($args:tt)* ) $new_arg_token:tt $($rest:tt)*) => {
try_gp_internal!(@ $status $out $func ( $($args)* $new_arg_token ) $($rest)*)
};
(@ $status:tt [ $($out:ident)* ] $func:ident $args:tt) => {
let ($status, $($out),*) = unsafe {
$(let mut $out = std::mem::MaybeUninit::uninit();)*
let status: std::os::raw::c_int = libgphoto2_sys::$func $args;
if status < 0 {
return Err($crate::Error::new(status));
}
(status, $($out.assume_init()),*)
};
};
(let $status:tt = $func:ident ( $($args:tt)* )) => {
try_gp_internal!(@ $status [] $func () $($args)*)
};
($func:ident ( $($args:tt)* )) => {
try_gp_internal!(@ _ [] $func () $($args)*)
};
}