1use crate::convert::ptr_to_string;
4use crate::ffi;
5use std::error;
6use std::fmt;
7use std::fmt::Display;
8use std::fmt::Formatter;
9use std::result;
10
11pub type Result<T> = result::Result<T, Error>;
13
14#[derive(Clone, Hash, Debug)]
16pub struct Error {
17 pub kind: Kind,
19 pub(crate) msg: String,
21}
22
23impl Error {
24 pub(crate) fn new(kind: Kind, msg: &str) -> Self {
26 Self { kind, msg: msg.to_owned() }
27 }
28
29 pub(crate) fn from_stack(stack: *const ffi::LIBMTP_error_t) -> Option<Self> {
31 if stack.is_null() {
32 return None;
33 }
34
35 let mut stack = stack;
36 let mut err = unsafe { *stack };
37
38 while !err.next.is_null() {
39 stack = err.next;
40 err = unsafe { *stack };
41 }
42
43 let kind = Kind::from_number(err.errornumber)?;
44 let msg = unsafe { ptr_to_string(err.error_text) };
45 Some(Self { kind, msg })
46 }
47}
48
49impl error::Error for Error {}
50
51impl Display for Error {
52 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
53 write!(f, "{}", self.msg)
54 }
55}
56
57impl Default for Error {
58 fn default() -> Self {
59 Self { kind: Default::default(), msg: "Unknown error".to_owned() }
60 }
61}
62
63#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Default)]
65pub enum Kind {
66 General,
68 PtpLayer,
70 UsbLayer,
72 MemoryAllocation,
74 NoDeviceAttached,
76 StorageFull,
78 Connecting,
80 Cancelled,
82 #[default]
84 Unknown,
85}
86
87impl Kind {
88 pub(crate) fn from_number(n: ffi::LIBMTP_error_number_t) -> Option<Self> {
90 match n {
91 ffi::LIBMTP_error_number_t::None => None,
92 ffi::LIBMTP_error_number_t::General => Some(Self::General),
93 ffi::LIBMTP_error_number_t::PtpLayer => Some(Self::PtpLayer),
94 ffi::LIBMTP_error_number_t::UsbLayer => Some(Self::UsbLayer),
95 ffi::LIBMTP_error_number_t::MemoryAllocation => Some(Self::MemoryAllocation),
96 ffi::LIBMTP_error_number_t::NoDeviceAttached => Some(Self::NoDeviceAttached),
97 ffi::LIBMTP_error_number_t::StorageFull => Some(Self::StorageFull),
98 ffi::LIBMTP_error_number_t::Connecting => Some(Self::Connecting),
99 ffi::LIBMTP_error_number_t::Cancelled => Some(Self::Cancelled),
100 }
101 }
102}