1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
use core::{ptr::NonNull, ffi::CStr};
use crate::AsPtr;
use sys::ffi;
use sys::error::fs::Error;
use sys::error::fs::Status;
use super::record::Record;
use super::Storage;
use super::Metadata;
use super::File;
use super::Path;
use super::FILE_NAME_LEN_MAX;
use super::Result;
pub struct ReadDir<const NAME_BUF_LEN: usize = { FILE_NAME_LEN_MAX as usize }, const WITH_INFO: bool = false>(File);
impl<T: Record> Storage<T> where [(); T::LEN]: Sized {
pub fn read_dir<P: AsRef<Path>>(&self, path: P) -> Result<ReadDir> {
let path = path.as_ref();
unsafe {
let dir = ffi::storage_file_alloc(self.0.as_ptr());
if ffi::storage_dir_open(dir, path.as_ptr() as _) {
} else {
ffi::storage_file_get_error(dir)?;
}
NonNull::new(dir).map(File).ok_or(Error::Internal).map(ReadDir::new)
}
}
}
impl<const NAME_BUF_LEN: usize, const WITH_INFO: bool> ReadDir<NAME_BUF_LEN, WITH_INFO> {
pub const fn new(file: File) -> Self { Self(file) }
}
impl<const NAME_BUF_LEN: usize> ReadDir<NAME_BUF_LEN, false> {
pub fn with_info(self) -> ReadDir<NAME_BUF_LEN, true> { ReadDir(self.0) }
}
impl<const CURRENT_BUF_LEN: usize, const WITH_INFO: bool> ReadDir<CURRENT_BUF_LEN, WITH_INFO> {
pub fn with_buf_len<const LEN: usize>(self) -> ReadDir<LEN, WITH_INFO> { ReadDir(self.0) }
}
impl<const LEN: usize, const INFO: bool> ReadDir<LEN, INFO> {
pub fn rewind(&mut self) -> Result<(), sys::error::fs::Error> {
let ptr = self.0.as_ptr();
unsafe {
if ffi::storage_dir_rewind(ptr) {
Ok(())
} else {
Ok(ffi::storage_file_get_error(ptr)?)
}
}
}
}
impl<const LEN: usize> Iterator for ReadDir<LEN, true> {
type Item = Result<Entry<ffi::FileInfo, LEN>>;
fn next(&mut self) -> Option<Self::Item> {
let mut entry = Entry::default();
unsafe {
let success = ffi::storage_dir_read(
self.0.as_ptr(),
(&mut entry.info) as *mut _,
entry.name.as_mut_ptr() as _,
LEN as u16,
);
if success {
Some(Ok(entry))
} else {
match ffi::storage_file_get_error(self.0.as_ptr()) {
Status::FSE_OK | Status::FSE_NOT_EXIST => None,
err => Some(Err(err.into())),
}
}
}
}
}
impl<const LEN: usize> Iterator for ReadDir<LEN, false> {
type Item = Result<Entry<(), LEN>>;
fn next(&mut self) -> Option<Self::Item> {
let mut entry = Entry::default();
unsafe {
let success = ffi::storage_dir_read(
self.0.as_ptr(),
core::ptr::null_mut(),
entry.name.as_mut_ptr() as _,
LEN as u16,
);
if success {
Some(Ok(entry))
} else {
match ffi::storage_file_get_error(self.0.as_ptr()) {
Status::FSE_OK | Status::FSE_NOT_EXIST => None,
err => Some(Err(err.into())),
}
}
}
}
}
#[derive(Debug)]
pub struct Entry<Info, const LEN: usize> {
name: [u8; LEN],
info: Info,
}
impl<Info, const LEN: usize> Entry<Info, LEN> {
pub fn file_name(&self) -> Result<&CStr, core::ffi::FromBytesUntilNulError> { CStr::from_bytes_until_nul(self.name.as_slice()) }
}
impl<const LEN: usize> Entry<ffi::FileInfo, LEN> {
pub fn metadata(&self) -> Metadata { Metadata(&self.info) }
}
impl<Info, const LEN: usize> Default for Entry<Info, LEN> {
fn default() -> Self {
Self { name: [0; LEN],
info: unsafe { core::mem::zeroed() } }
}
}
impl<Info, const LEN: usize> core::fmt::Display for Entry<Info, LEN> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self.file_name().map_err(|_| core::fmt::Error)?,)
}
}