1use core::{
4 ffi::c_int,
5 fmt::{self, Debug, Formatter},
6};
7
8pub trait Read {
10 fn read(&self, buf: &mut [u8]) -> Result<usize>;
13
14 fn read_exact(&self, buf: &mut [u8]) -> Result<()> {
15 let len = self.read(buf)?;
17 if len == buf.len() {
18 Ok(())
19 } else {
20 Err(Error::IO)
22 }
23 }
24}
25
26pub trait Write {
33 fn write(&self, data: &[u8]) -> Result<usize>;
38
39 fn flush(&self) -> Result<()>;
41
42 fn write_all(&self, mut buf: &[u8]) -> Result<()> {
43 while !buf.is_empty() {
44 match self.write(buf) {
45 Ok(0) => {
46 return Err(Error::IO);
48 }
49 Ok(n) => buf = &buf[n..],
50 Err(e) => return Err(e),
51 }
52 }
53 Ok(())
54 }
55}
56
57#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62pub enum SeekFrom {
63 Start(u32),
64 End(i32),
65 Current(i32),
66}
67
68impl SeekFrom {
69 pub fn off(self) -> i32 {
70 match self {
71 SeekFrom::Start(u) => u as i32,
72 SeekFrom::End(i) => i,
73 SeekFrom::Current(i) => i,
74 }
75 }
76
77 pub fn whence(self) -> c_int {
78 match self {
79 SeekFrom::Start(_) => 0,
80 SeekFrom::End(_) => 2,
81 SeekFrom::Current(_) => 1,
82 }
83 }
84}
85
86#[derive(Clone, Copy, Debug, Eq, PartialEq)]
90pub enum OpenSeekFrom {
91 Start(u32),
92 End(i32),
93}
94
95impl From<OpenSeekFrom> for SeekFrom {
96 fn from(value: OpenSeekFrom) -> Self {
97 match value {
98 OpenSeekFrom::Start(o) => Self::Start(o),
99 OpenSeekFrom::End(o) => Self::End(o),
100 }
101 }
102}
103
104pub trait Seek {
109 fn seek(&self, pos: SeekFrom) -> Result<usize>;
112}
113
114pub type Result<T, E = Error> = core::result::Result<T, E>;
115
116#[derive(Clone, Copy, PartialEq)]
126pub struct Error {
127 code: c_int,
128}
129
130impl Error {
131 pub const IO: Self = Self::new_const(-5);
133
134 pub const CORRUPTION: Self = Self::new_const(-84);
136
137 pub const NO_SUCH_ENTRY: Self = Self::new_const(-2);
139
140 pub const ENTRY_ALREADY_EXISTED: Self = Self::new_const(-17);
142
143 pub const PATH_NOT_DIR: Self = Self::new_const(-20);
145
146 pub const PATH_IS_DIR: Self = Self::new_const(-21);
148
149 pub const DIR_NOT_EMPTY: Self = Self::new_const(-39);
151
152 pub const BAD_FILE_DESCRIPTOR: Self = Self::new_const(-9);
154
155 pub const FILE_TOO_BIG: Self = Self::new_const(-27);
157
158 pub const INVALID: Self = Self::new_const(-22);
160
161 pub const NO_SPACE: Self = Self::new_const(-28);
163
164 pub const NO_MEMORY: Self = Self::new_const(-12);
166
167 pub const NO_ATTRIBUTE: Self = Self::new_const(-61);
169
170 pub const FILENAME_TOO_LONG: Self = Self::new_const(-36);
172
173 pub const fn new(code: c_int) -> Option<Self> {
178 if code >= 0 {
179 None
180 } else {
181 Some(Self { code })
182 }
183 }
184
185 const fn new_const(code: c_int) -> Self {
186 if code >= 0 {
187 panic!("error code must be negative");
188 }
189 Self { code }
190 }
191
192 pub const fn code(&self) -> c_int {
194 self.code
195 }
196}
197
198impl Debug for Error {
204 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
205 #[cfg(not(feature = "debug-error"))]
206 {
207 f.debug_struct("Error").finish()
208 }
209 #[cfg(feature = "debug-error")]
210 {
211 match self {
212 &Self::IO => f.write_str("IO"),
213 &Self::CORRUPTION => f.write_str("CORRUPTION"),
214 &Self::NO_SUCH_ENTRY => f.write_str("NO_SUCH_ENTRY"),
215 &Self::ENTRY_ALREADY_EXISTED => f.write_str("ENTRY_ALREADY_EXISTED"),
216 &Self::PATH_NOT_DIR => f.write_str("PATH_NOT_DIR"),
217 &Self::PATH_IS_DIR => f.write_str("PATH_IS_DIR"),
218 &Self::DIR_NOT_EMPTY => f.write_str("DIR_NOT_EMPTY"),
219 &Self::BAD_FILE_DESCRIPTOR => f.write_str("BAD_FILE_DESCRIPTOR"),
220 &Self::FILE_TOO_BIG => f.write_str("FILE_TOO_BIG"),
221 &Self::INVALID => f.write_str("INVALID"),
222 &Self::NO_SPACE => f.write_str("NO_SPACE"),
223 &Self::NO_MEMORY => f.write_str("NO_MEMORY"),
224 &Self::NO_ATTRIBUTE => f.write_str("NO_ATTRIBUTE"),
225 &Self::FILENAME_TOO_LONG => f.write_str("FILENAME_TOO_LONG"),
226 other => f.debug_tuple("Error").field(&other.code).finish(),
227 }
228 }
229 }
230}
231
232impl From<Error> for c_int {
233 fn from(error: Error) -> Self {
234 error.code
235 }
236}