file_system/fundamentals/
entry.rs1use alloc::string::String;
8
9use crate::Kind;
10
11use super::{Inode, Size};
12
13#[derive(Clone, Debug, PartialEq, Eq)]
39pub struct Entry {
40 inode: Inode,
42 name: String,
44 r#type: Kind,
46 size: Size,
48}
49
50impl Entry {
51 pub fn new(inode: Inode, name: String, r#type: Kind, size: Size) -> Self {
75 Self {
76 inode,
77 name,
78 r#type,
79 size,
80 }
81 }
82
83 pub fn get_inode(&self) -> Inode {
89 self.inode
90 }
91
92 pub fn get_name(&self) -> &String {
98 &self.name
99 }
100
101 pub fn get_type(&self) -> Kind {
107 self.r#type
108 }
109
110 pub fn get_size(&self) -> Size {
117 self.size
118 }
119
120 pub fn set_inode(&mut self, inode: Inode) {
126 self.inode = inode;
127 }
128
129 pub fn set_name(&mut self, name: String) {
135 self.name = name;
136 }
137
138 pub fn set_type(&mut self, r#type: Kind) {
144 self.r#type = r#type;
145 }
146
147 pub fn set_size(&mut self, size: Size) {
148 self.size = size;
149 }
150}
151
152impl AsMut<[u8]> for Entry {
153 fn as_mut(&mut self) -> &mut [u8] {
154 unsafe {
155 core::slice::from_raw_parts_mut(
156 self as *mut Entry as *mut u8,
157 core::mem::size_of::<Entry>(),
158 )
159 }
160 }
161}
162
163impl TryFrom<&mut [u8]> for &mut Entry {
164 type Error = ();
165
166 fn try_from(value: &mut [u8]) -> Result<Self, Self::Error> {
167 if value.len() != core::mem::size_of::<Entry>() {
168 return Err(());
169 }
170 if !(value.as_ptr() as usize).is_multiple_of(core::mem::align_of::<Entry>()) {
171 return Err(());
172 }
173
174 #[allow(clippy::transmute_ptr_to_ref)]
175 Ok(unsafe { core::mem::transmute::<*mut u8, &mut Entry>(value.as_mut_ptr()) })
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use alloc::string::String;
183
184 #[test]
185 fn test_entry_creation() {
186 let entry = Entry::new(
187 Inode::new(42),
188 String::from("test.txt"),
189 Kind::File,
190 Size::new(1024),
191 );
192
193 assert_eq!(entry.get_inode(), Inode::new(42));
194 assert_eq!(entry.get_name(), "test.txt");
195 assert_eq!(entry.get_type(), Kind::File);
196 assert_eq!(entry.get_size(), Size::new(1024));
197 }
198
199 #[test]
200 fn test_entry_getters() {
201 let entry = Entry::new(
202 Inode::new(123),
203 String::from("directory"),
204 Kind::Directory,
205 Size::new(0),
206 );
207
208 assert_eq!(entry.get_inode().as_u64(), 123);
210 assert_eq!(entry.get_name(), "directory");
211 assert_eq!(entry.get_type(), Kind::Directory);
212 assert_eq!(entry.get_size().as_u64(), 0);
213 }
214
215 #[test]
216 fn test_entry_setters() {
217 let mut entry = Entry::new(
218 Inode::new(1),
219 String::from("old_name"),
220 Kind::File,
221 Size::new(100),
222 );
223
224 entry.set_inode(Inode::new(999));
226 entry.set_name(String::from("new_name.txt"));
227 entry.set_type(Kind::Directory);
228 entry.set_size(Size::new(2048));
229
230 assert_eq!(entry.get_inode().as_u64(), 999);
232 assert_eq!(entry.get_name(), "new_name.txt");
233 assert_eq!(entry.get_type(), Kind::Directory);
234 assert_eq!(entry.get_size().as_u64(), 2048);
235 }
236
237 #[test]
238 fn test_entry_clone() {
239 let original = Entry::new(
240 Inode::new(456),
241 String::from("clone_test.dat"),
242 Kind::File,
243 Size::new(512),
244 );
245
246 let cloned = original.clone();
247
248 assert_eq!(original.get_inode(), cloned.get_inode());
250 assert_eq!(original.get_name(), cloned.get_name());
251 assert_eq!(original.get_type(), cloned.get_type());
252 assert_eq!(original.get_size(), cloned.get_size());
253
254 assert_eq!(original, cloned);
256 }
257
258 #[test]
259 fn test_entry_debug() {
260 let entry = Entry::new(
261 Inode::new(789),
262 String::from("debug_test"),
263 Kind::SymbolicLink,
264 Size::new(64),
265 );
266
267 let debug_str = alloc::format!("{entry:?}");
268 assert!(debug_str.contains("Entry_type"));
269 assert!(debug_str.contains("789"));
270 assert!(debug_str.contains("debug_test"));
271 }
272
273 #[test]
274 fn test_entry_equality() {
275 let entry1 = Entry::new(
276 Inode::new(100),
277 String::from("same.txt"),
278 Kind::File,
279 Size::new(200),
280 );
281
282 let entry2 = Entry::new(
283 Inode::new(100),
284 String::from("same.txt"),
285 Kind::File,
286 Size::new(200),
287 );
288
289 let entry3 = Entry::new(
290 Inode::new(101),
291 String::from("different.txt"),
292 Kind::File,
293 Size::new(200),
294 );
295
296 assert_eq!(entry1, entry2);
297 assert_ne!(entry1, entry3);
298 }
299
300 #[test]
301 fn test_entry_different_types() {
302 let file_entry = Entry::new(
304 Inode::new(1),
305 String::from("file.txt"),
306 Kind::File,
307 Size::new(1024),
308 );
309
310 let dir_entry = Entry::new(
311 Inode::new(2),
312 String::from("directory"),
313 Kind::Directory,
314 Size::new(0),
315 );
316
317 let symlink_entry = Entry::new(
318 Inode::new(3),
319 String::from("link"),
320 Kind::SymbolicLink,
321 Size::new(32),
322 );
323
324 assert_eq!(file_entry.get_type(), Kind::File);
325 assert_eq!(dir_entry.get_type(), Kind::Directory);
326 assert_eq!(symlink_entry.get_type(), Kind::SymbolicLink);
327
328 assert_ne!(file_entry, dir_entry);
329 assert_ne!(dir_entry, symlink_entry);
330 assert_ne!(file_entry, symlink_entry);
331 }
332
333 #[test]
334 fn test_entry_empty_name() {
335 let entry = Entry::new(Inode::new(0), String::new(), Kind::File, Size::new(0));
336
337 assert_eq!(entry.get_name(), "");
338 assert_eq!(entry.get_name().len(), 0);
339 }
340
341 #[test]
342 fn test_entry_large_values() {
343 let entry = Entry::new(
344 Inode::new(u64::MAX),
345 String::from("large_file.bin"),
346 Kind::File,
347 Size::new(u64::MAX),
348 );
349
350 assert_eq!(entry.get_inode().as_u64(), u64::MAX);
351 assert_eq!(entry.get_size().as_u64(), u64::MAX);
352 }
353
354 #[test]
355 fn test_entry_as_mut_slice() {
356 let mut entry = Entry::new(
357 Inode::new(42),
358 String::from("test"),
359 Kind::File,
360 Size::new(100),
361 );
362
363 let slice = entry.as_mut();
364 assert_eq!(slice.len(), core::mem::size_of::<Entry>());
365 }
366
367 #[test]
368 fn test_entry_from_slice_invalid_size() {
369 let mut buffer = [0u8; 10]; let result = <&mut Entry>::try_from(buffer.as_mut_slice());
371 assert!(result.is_err());
372 }
373
374 #[test]
375 fn test_entry_from_slice_valid() {
376 let mut buffer = alloc::vec![0u8; core::mem::size_of::<Entry>()];
378
379 let result = <&mut Entry>::try_from(buffer.as_mut_slice());
381
382 let _ = result; }
386
387 #[test]
388 fn test_entry_modification_after_creation() {
389 let mut entry = Entry::new(
390 Inode::new(1),
391 String::from("initial"),
392 Kind::File,
393 Size::new(0),
394 );
395
396 for i in 1..=5 {
398 entry.set_inode(Inode::new(i));
399 entry.set_name(alloc::format!("name_{i}"));
400 entry.set_size(Size::new(i * 100));
401
402 assert_eq!(entry.get_inode().as_u64(), i);
403 assert_eq!(entry.get_name(), &alloc::format!("name_{i}"));
404 assert_eq!(entry.get_size().as_u64(), i * 100);
405 }
406 }
407
408 #[test]
409 fn test_entry_unicode_names() {
410 let entry = Entry::new(
411 Inode::new(1),
412 String::from("файл.txt"), Kind::File,
414 Size::new(256),
415 );
416
417 assert_eq!(entry.get_name(), "файл.txt");
418
419 let entry2 = Entry::new(
420 Inode::new(2),
421 String::from("文件.dat"), Kind::File,
423 Size::new(512),
424 );
425
426 assert_eq!(entry2.get_name(), "文件.dat");
427 }
428}