Skip to main content

vfat_rs/api/
directory_entry.rs

1use crate::api::timestamp::VfatTimestamp;
2use crate::api::{Directory, File, Metadata};
3use crate::{Result, VfatFS};
4
5/// This is a library's user interface. Each directory can contain either a File or a Directory.
6#[derive(Debug)]
7enum EntryKind {
8    File,
9    Directory,
10}
11/// Common metadata accessors shared by [`File`], [`Directory`], and [`DirectoryEntry`].
12pub trait VfatMetadataTrait {
13    /// Returns a reference to the entry's [`Metadata`].
14    fn metadata(&self) -> &Metadata;
15    /// Returns the entry's name.
16    fn name(&self) -> &str {
17        self.metadata().name()
18    }
19    /// Returns the entry's creation timestamp.
20    fn creation(&self) -> VfatTimestamp {
21        self.metadata().creation().unwrap()
22    }
23}
24impl VfatMetadataTrait for DirectoryEntry {
25    fn metadata(&self) -> &Metadata {
26        &self.metadata
27    }
28}
29
30/// A directory entry: either a file or a directory.
31#[derive(Debug)]
32pub struct DirectoryEntry {
33    kind: EntryKind,
34    /// Metadata for this entry (name, path, cluster, timestamps, etc.).
35    pub metadata: Metadata,
36    vfat_filesystem: VfatFS,
37}
38impl DirectoryEntry {
39    /// Create a new file-typed directory entry.
40    pub fn new_file(metadata: Metadata, vfat_filesystem: VfatFS) -> Self {
41        Self {
42            kind: EntryKind::File,
43            metadata,
44            vfat_filesystem,
45        }
46    }
47    /// Create a new directory-typed directory entry.
48    pub fn new_directory(metadata: Metadata, vfat_filesystem: VfatFS) -> Self {
49        Self {
50            kind: EntryKind::Directory,
51            metadata,
52            vfat_filesystem,
53        }
54    }
55}
56
57impl DirectoryEntry {
58    pub(crate) fn is_dir(&self) -> bool {
59        matches!(&self.kind, EntryKind::Directory)
60    }
61
62    /// Convert into a [`Directory`], returning `None` if this is a file.
63    pub fn into_directory(self) -> Option<Directory> {
64        self.is_dir()
65            .then(|| Directory::new(self.vfat_filesystem, self.metadata))
66    }
67    /// Convert into a [`Directory`] without checking the entry kind.
68    pub fn into_directory_unchecked(self) -> Directory {
69        Directory::new(self.vfat_filesystem, self.metadata)
70    }
71    /// Convert into a [`Directory`], returning [`VfatRsError::EntryNotFound`] if this is a file.
72    pub fn into_directory_or_not_found(self) -> Result<Directory> {
73        if self.is_dir() {
74            Ok(self.into_directory_unchecked())
75        } else {
76            Err(crate::error::VfatRsError::EntryNotFound {
77                target: self.metadata.name().into(),
78            })
79        }
80    }
81    fn is_file(&self) -> bool {
82        !self.is_dir()
83    }
84    /// Convert into a [`File`], returning `None` if this is a directory.
85    pub fn into_file(self) -> Option<File> {
86        self.is_file()
87            .then(|| File::new(self.vfat_filesystem, self.metadata))
88    }
89    /// Convert into a [`File`], panicking if this is a directory.
90    pub fn into_file_unchecked(self) -> File {
91        self.is_file()
92            .then(|| File::new(self.vfat_filesystem, self.metadata))
93            .unwrap()
94    }
95}
96
97impl From<Directory> for DirectoryEntry {
98    fn from(directory: Directory) -> Self {
99        DirectoryEntry::new_directory(directory.metadata, directory.vfat_filesystem)
100    }
101}