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::io;
10use std::result;
11
12pub type Result<T> = result::Result<T, Error>;
14
15#[derive(Clone, Hash, Debug)]
17pub struct Error {
18 kind: ErrorKind,
20 text: String,
22}
23
24impl Error {
25 pub(crate) fn new(kind: ErrorKind, text: &str) -> Self {
27 Self { kind, text: text.to_owned() }
28 }
29
30 pub(crate) fn from_ffi(ptr: *const ffi::LIBMTP_error_t) -> Option<Self> {
32 if ptr.is_null() {
33 return None;
34 }
35
36 let mut ptr = ptr;
37 let mut err = unsafe { *ptr };
38
39 while !err.next.is_null() {
40 ptr = err.next;
41 err = unsafe { *ptr };
42 }
43
44 let kind = MtpErrorKind::new(err.errornumber)?;
45 let text = unsafe { ptr_to_string(err.error_text) };
46 Some(Self { kind: ErrorKind::Mtp(kind), text })
47 }
48}
49
50impl error::Error for Error {}
51
52impl Display for Error {
53 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
54 write!(f, "{}", self.text)
55 }
56}
57
58#[doc(hidden)]
59impl Default for Error {
60 fn default() -> Self {
61 Self { kind: ErrorKind::default(), text: "Unknown error".to_owned() }
62 }
63}
64
65#[doc(hidden)]
66impl From<io::Error> for Error {
67 fn from(e: io::Error) -> Self {
68 Self::new(ErrorKind::Io, &e.to_string())
69 }
70}
71
72#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
74pub enum ErrorKind {
75 Mtp(MtpErrorKind),
77 Io,
79 Unknown,
81}
82
83#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
85pub enum MtpErrorKind {
86 General,
88 Ptp,
90 Usb,
92 MemoryAllocation,
94 NoDeviceAttached,
96 StorageFull,
98 Connecting,
100 Cancelled,
102}
103
104impl MtpErrorKind {
105 pub(crate) fn new(n: ffi::LIBMTP_error_number_t) -> Option<Self> {
107 match n {
108 ffi::LIBMTP_error_number_t::None => None,
109 ffi::LIBMTP_error_number_t::General => Some(Self::General),
110 ffi::LIBMTP_error_number_t::PtpLayer => Some(Self::Ptp),
111 ffi::LIBMTP_error_number_t::UsbLayer => Some(Self::Usb),
112 ffi::LIBMTP_error_number_t::MemoryAllocation => Some(Self::MemoryAllocation),
113 ffi::LIBMTP_error_number_t::NoDeviceAttached => Some(Self::NoDeviceAttached),
114 ffi::LIBMTP_error_number_t::StorageFull => Some(Self::StorageFull),
115 ffi::LIBMTP_error_number_t::Connecting => Some(Self::Connecting),
116 ffi::LIBMTP_error_number_t::Cancelled => Some(Self::Cancelled),
117 }
118 }
119}
120
121#[doc(hidden)]
122#[allow(clippy::derivable_impls)]
123impl Default for ErrorKind {
124 fn default() -> Self {
125 ErrorKind::Unknown
126 }
127}