file_system/fundamentals/
flags.rs

1use core::fmt::Debug;
2
3use shared::flags;
4
5use super::Permission;
6
7flags! {
8    /// The flags for opening a file.
9    pub enum AccessFlags: u8 {
10        /// Read permission.
11        Read,
12        /// Write permission.
13        Write,
14    }
15}
16
17impl AccessFlags {
18    pub const READ_WRITE: Self = Self::None.insert(Self::Read).insert(Self::Write);
19
20    pub const fn into_permission(&self) -> Permission {
21        let mut permission = Permission::None;
22
23        if self.contains(AccessFlags::Read) {
24            permission = permission.insert(Permission::Read);
25        }
26
27        if self.contains(AccessFlags::Write) {
28            permission = permission.insert(Permission::Write);
29        }
30
31        permission
32    }
33}
34
35flags! {
36    /// The flags for opening a file.
37    pub enum CreateFlags: u8 {
38        /// Create the file if it does not exist.
39        Create,
40        /// Fail if the file already exists.
41        Exclusive,
42        /// Truncate the file to zero length if it exists.
43        Truncate,
44    }
45}
46
47impl CreateFlags {
48    pub const CREATE_TRUNCATE: Self = Self::Create.insert(Self::Truncate);
49    pub const CREATE_EXCLUSIVE: Self = Self::Create.insert(Self::Exclusive);
50}
51
52flags! {
53    /// The status flags of a file.
54    pub enum StateFlags: u8 {
55        /// Append mode.
56        Append,
57        /// Non-blocking mode.
58        NonBlocking,
59        /// Synchronous mode.
60        Synchronous,
61        /// Synchronous data only mode.
62        SynchronousDataOnly,
63    }
64}
65
66/// All the flags that can be set for a file.
67///
68/// The flags are stored in a 16-bit integer, with the following layout:
69///
70/// | Mode | Open | Status |
71/// |------|------|--------|
72/// | 0-1  | 2-5  | 6-9    |
73///
74/// # Example
75///
76/// ```rust
77/// use file_system::{Flags, AccessFlags, CreateFlags, StateFlags};
78///     
79/// let flags = Flags::new(AccessFlags::READ_WRITE, Some(CreateFlags::Create), Some(StateFlags::NonBlocking));
80///
81/// assert_eq!(flags.get_access(), AccessFlags::READ_WRITE);
82/// assert_eq!(flags.get_create(), CreateFlags::Create);
83/// assert_eq!(flags.get_state(), StateFlags::NonBlocking);
84/// ```
85#[derive(PartialEq, Eq, Clone, Copy)]
86#[repr(transparent)]
87pub struct Flags(u16);
88
89impl Debug for Flags {
90    fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
91        formatter
92            .debug_struct("Flags")
93            .field("Access", &self.get_access())
94            .field("Create", &self.get_create())
95            .field("State", &self.get_state())
96            .finish()
97    }
98}
99
100impl Flags {
101    const MODE_POSITION: u8 = 0;
102    const OPEN_POSITION: u8 = AccessFlags::bits_used();
103    const STATUS_POSITION: u8 = CreateFlags::bits_used() + Self::OPEN_POSITION;
104
105    const OPEN_MASK: u16 = (1 << CreateFlags::bits_used()) - 1;
106    const STATUS_MASK: u16 = (1 << StateFlags::bits_used()) - 1;
107    const MODE_MASK: u16 = (1 << AccessFlags::bits_used()) - 1;
108
109    pub const fn new(
110        mode: AccessFlags,
111        open: Option<CreateFlags>,
112        status: Option<StateFlags>,
113    ) -> Self {
114        let open = if let Some(open_val) = open {
115            open_val
116        } else {
117            CreateFlags::None
118        };
119        let status = if let Some(status_val) = status {
120            status_val
121        } else {
122            StateFlags::None
123        };
124
125        let mut flags: u16 = 0;
126        flags |= (mode.0 as u16) << Self::MODE_POSITION;
127        flags |= (open.0 as u16) << Self::OPEN_POSITION;
128        flags |= (status.0 as u16) << Self::STATUS_POSITION;
129        Self(flags)
130    }
131
132    pub const fn get_access(&self) -> AccessFlags {
133        AccessFlags(((self.0 >> Self::MODE_POSITION) & Self::MODE_MASK) as u8)
134    }
135
136    pub const fn get_create(&self) -> CreateFlags {
137        CreateFlags(((self.0 >> Self::OPEN_POSITION) & Self::OPEN_MASK) as u8)
138    }
139
140    pub const fn get_state(&self) -> StateFlags {
141        StateFlags(((self.0 >> Self::STATUS_POSITION) & Self::STATUS_MASK) as u8)
142    }
143
144    pub const fn set_mode(mut self, mode: AccessFlags) -> Self {
145        self.0 &= !(Self::MODE_MASK << Self::MODE_POSITION);
146        self.0 |= (mode.0 as u16) << Self::MODE_POSITION;
147        self
148    }
149
150    pub const fn set_open(mut self, open: CreateFlags) -> Self {
151        self.0 &= !(Self::OPEN_MASK << Self::OPEN_POSITION);
152        self.0 |= (open.0 as u16) << Self::OPEN_POSITION;
153        self
154    }
155
156    pub const fn set_status(mut self, status: StateFlags) -> Self {
157        self.0 &= !(Self::STATUS_MASK << Self::STATUS_POSITION);
158        self.0 |= (status.0 as u16) << Self::STATUS_POSITION;
159        self
160    }
161
162    pub fn is_permission_granted(&self, permission: &Permission) -> bool {
163        let mode = self.get_access();
164
165        let read = permission.contains(Permission::Read) && mode.contains(AccessFlags::Read); // Read permission
166        let write = permission.contains(Permission::Write)
167            && (mode.contains(AccessFlags::Write) || self.get_state().contains(StateFlags::Append)); // Write permission
168
169        read || write
170    }
171
172    pub fn split(&self) -> (AccessFlags, CreateFlags, StateFlags) {
173        (self.get_access(), self.get_create(), self.get_state())
174    }
175}
176
177impl From<AccessFlags> for Flags {
178    fn from(mode: AccessFlags) -> Self {
179        Self::new(mode, None, None)
180    }
181}
182
183impl From<Flags> for u16 {
184    fn from(flags: Flags) -> Self {
185        flags.0
186    }
187}
188
189#[cfg(test)]
190mod tests {
191    use super::*;
192
193    #[test]
194    fn test_flags_type_set_get() {
195        let flags = Flags::new(AccessFlags::Read, None, None);
196
197        let new_mode = AccessFlags::Write;
198        let flags = flags.set_mode(new_mode);
199        assert_eq!(flags.get_access(), new_mode);
200
201        let new_open = CreateFlags::Exclusive | CreateFlags::Truncate;
202        let flags = flags.set_open(new_open);
203        assert_eq!(flags.get_create(), new_open);
204
205        let new_status = StateFlags::NonBlocking | StateFlags::SynchronousDataOnly;
206        let flags = flags.set_status(new_status);
207        assert_eq!(flags.get_state(), new_status);
208    }
209
210    #[test]
211    fn test_flags_type_is_permission_granted() {
212        let mode = AccessFlags::READ_WRITE;
213        let status = StateFlags::None;
214        let flags = Flags::new(mode, None, Some(status));
215
216        assert!(flags.is_permission_granted(&Permission::Read));
217        assert!(flags.is_permission_granted(&Permission::Write));
218        assert!(flags.is_permission_granted(&Permission::READ_WRITE));
219    }
220
221    #[test]
222    fn test_flags_type_from_mode_type() {
223        let mode = AccessFlags::READ_WRITE;
224        let flags: Flags = mode.into();
225        assert_eq!(flags.get_access(), mode);
226    }
227
228    #[test]
229    fn test_flags_type_into_u16() {
230        let mode = AccessFlags::READ_WRITE;
231        let flags = Flags::new(mode, None, None);
232        let flags_u16: u16 = flags.into();
233        assert_eq!(flags_u16, flags.0);
234    }
235}