1use crate::ffi;
2use std::borrow::{Borrow, BorrowMut};
3use std::ffi::CStr;
4use std::fmt;
5use std::mem::zeroed;
6use std::ops::{Deref, DerefMut};
7use std::os::raw::c_int;
8
9#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
10pub enum System {
11 Sys(c_int),
12 Zlib(c_int),
13 Unknown(c_int),
14}
15
16#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub enum Zip {
18 Changed,
19 Close,
20 CompressionNotSupported,
21 CompressedDataInvalid,
22 Crc,
23 Deleted,
24 EncryptionNotSupported,
25 Eof,
26 Exists,
27 Inconsistent,
28 Internal,
29 InUse,
30 InvalidArgument,
31 Memory,
32 Multidisk,
33 NoSuchFile,
34 NoPassword,
35 NotZip,
36 Open,
37 OperationNotSupported,
38 ReadOnly,
39 Read,
40 Remove,
41 Rename,
42 Seek,
43 Tell,
44 TempFile,
45 Write,
46 WrongPassword,
47 ZipClosed,
48 Zlib,
49 Unknown,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
53pub struct Error {
54 pub system: Option<System>,
55 pub zip: Option<Zip>,
56 message: String,
57}
58
59impl fmt::Display for Error {
60 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61 write!(f, "Error: {}", self.message)
62 }
63}
64
65impl std::error::Error for Error {}
66
67pub type Result<T> = std::result::Result<T, Error>;
68
69#[derive(Debug)]
73pub(crate) struct ZipErrorT<T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>> {
74 error: T,
75 cleanup: bool,
76}
77
78impl Default for ZipErrorT<ffi::zip_error_t> {
79 fn default() -> Self {
80 unsafe {
81 let mut handle: ffi::zip_error_t = zeroed();
82 ffi::zip_error_init(&mut handle);
83 ZipErrorT {
84 error: handle,
85 cleanup: true,
86 }
87 }
88 }
89}
90
91impl From<c_int> for ZipErrorT<ffi::zip_error_t> {
92 fn from(error: c_int) -> Self {
93 unsafe {
94 let mut handle: ffi::zip_error_t = zeroed();
95 ffi::zip_error_init_with_code(&mut handle, error);
96 ZipErrorT {
97 error: handle,
98 cleanup: true,
99 }
100 }
101 }
102}
103
104impl<'a> From<&'a mut ffi::zip_error_t> for ZipErrorT<&'a mut ffi::zip_error_t> {
105 fn from(error: &'a mut ffi::zip_error_t) -> Self {
106 ZipErrorT {
107 error,
108 cleanup: false,
109 }
110 }
111}
112
113impl<T> ZipErrorT<T>
114where
115 T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
116{
117 pub fn system(&self) -> Option<System> {
118 let system = unsafe { ffi::zip_error_system_type(self.deref()) };
119 match system as _ {
120 ffi::ZIP_ET_NONE => None,
121 _ => {
122 let code = unsafe { ffi::zip_error_code_system(self.deref()) };
123 Some(match system as _ {
124 ffi::ZIP_ET_SYS => System::Sys(code),
125 ffi::ZIP_ET_ZLIB => System::Zlib(code),
126 _ => System::Unknown(code),
127 })
128 }
129 }
130 }
131 pub fn zip(&self) -> Option<Zip> {
132 let code = unsafe { ffi::zip_error_code_zip(self.deref()) };
133 Some(match code as _ {
134 ffi::ZIP_ER_CHANGED => Zip::Changed,
135 ffi::ZIP_ER_CLOSE => Zip::Close,
136 ffi::ZIP_ER_COMPNOTSUPP => Zip::CompressionNotSupported,
137 ffi::ZIP_ER_COMPRESSED_DATA => Zip::CompressedDataInvalid,
138 ffi::ZIP_ER_CRC => Zip::Crc,
139 ffi::ZIP_ER_DELETED => Zip::Deleted,
140 ffi::ZIP_ER_ENCRNOTSUPP => Zip::EncryptionNotSupported,
141 ffi::ZIP_ER_EOF => Zip::Eof,
142 ffi::ZIP_ER_EXISTS => Zip::Exists,
143 ffi::ZIP_ER_INCONS => Zip::Inconsistent,
144 ffi::ZIP_ER_INTERNAL => Zip::Internal,
145 ffi::ZIP_ER_INUSE => Zip::InUse,
146 ffi::ZIP_ER_INVAL => Zip::InvalidArgument,
147 ffi::ZIP_ER_MEMORY => Zip::Memory,
148 ffi::ZIP_ER_MULTIDISK => Zip::Multidisk,
149 ffi::ZIP_ER_NOENT => Zip::NoSuchFile,
150 ffi::ZIP_ER_NOPASSWD => Zip::NoPassword,
151 ffi::ZIP_ER_NOZIP => Zip::NotZip,
152 ffi::ZIP_ER_OK => return None,
153 ffi::ZIP_ER_OPEN => Zip::Open,
154 ffi::ZIP_ER_OPNOTSUPP => Zip::OperationNotSupported,
155 ffi::ZIP_ER_RDONLY => Zip::ReadOnly,
156 ffi::ZIP_ER_READ => Zip::Read,
157 ffi::ZIP_ER_REMOVE => Zip::Remove,
158 ffi::ZIP_ER_RENAME => Zip::Rename,
159 ffi::ZIP_ER_SEEK => Zip::Seek,
160 ffi::ZIP_ER_TELL => Zip::Tell,
161 ffi::ZIP_ER_TMPOPEN => Zip::TempFile,
162 ffi::ZIP_ER_WRITE => Zip::Write,
163 ffi::ZIP_ER_WRONGPASSWD => Zip::WrongPassword,
164 ffi::ZIP_ER_ZIPCLOSED => Zip::ZipClosed,
165 ffi::ZIP_ER_ZLIB => Zip::Zlib,
166 _ => Zip::Unknown,
167 })
168 }
169
170 pub fn message(&mut self) -> &CStr {
171 unsafe {
172 let message = ffi::zip_error_strerror(self.deref_mut());
173 assert!(!message.is_null());
174 CStr::from_ptr(message)
175 }
176 }
177}
178
179impl<T> Drop for ZipErrorT<T>
180where
181 T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
182{
183 fn drop(&mut self) {
184 if self.cleanup {
185 unsafe { ffi::zip_error_fini(self.error.borrow_mut()) }
186 }
187 }
188}
189
190impl<T> Deref for ZipErrorT<T>
191where
192 T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
193{
194 type Target = ffi::zip_error_t;
195 fn deref(&self) -> &Self::Target {
196 self.error.borrow()
197 }
198}
199
200impl<T> DerefMut for ZipErrorT<T>
201where
202 T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
203{
204 fn deref_mut(&mut self) -> &mut Self::Target {
205 self.error.borrow_mut()
206 }
207}
208
209impl<T> From<ZipErrorT<T>> for Error
210where
211 T: Borrow<ffi::zip_error_t> + BorrowMut<ffi::zip_error_t>,
212{
213 fn from(mut error: ZipErrorT<T>) -> Self {
214 let system = error.system();
215 let zip = error.zip();
216 let message = error.message().to_string_lossy().into_owned();
217 Error {
218 system,
219 zip,
220 message,
221 }
222 }
223}