abi_context/file.rs
1//! File identifier types for opened files.
2//!
3//! This module provides file identifier types used to identify opened files
4//! within a task's file descriptor table, similar to file descriptors in
5//! Unix-like systems.
6
7use crate::UniqueFileIdentifier;
8use core::num::NonZero;
9use task::TaskIdentifier;
10
11pub type FileIdentifierInner = u16;
12
13/// Type-safe wrapper for file identifiers.
14///
15/// File identifiers are used to reference opened files within a task's context,
16/// similar to file descriptors in Unix-like systems. Each task maintains its own
17/// file identifier space, allowing for task isolation and security.
18///
19/// # Standard File Identifiers
20///
21/// The following standard identifiers are predefined:
22/// - [`FileIdentifier::STANDARD_IN`] (0) - Standard input
23/// - [`FileIdentifier::STANDARD_OUT`] (1) - Standard output
24/// - [`FileIdentifier::STANDARD_ERROR`] (2) - Standard error
25///
26/// # Examples
27///
28/// ```rust
29/// use abi_context::FileIdentifier;
30///
31/// // Standard file identifiers
32/// assert_eq!(1u16, FileIdentifier::STANDARD_IN.into());
33/// assert_eq!(2u16, FileIdentifier::STANDARD_OUT.into());
34/// assert_eq!(3u16, FileIdentifier::STANDARD_ERROR.into());
35///
36/// // Create a custom file identifier
37/// let file_id = FileIdentifier::new(42).unwrap();
38/// assert_eq!(42u16, file_id.into());
39/// ```
40#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
41#[repr(transparent)]
42pub struct FileIdentifier(NonZero<u16>);
43
44impl FileIdentifier {
45 /// Size in bits of the underlying identifier type.
46 pub const SIZE_BITS: u8 = core::mem::size_of::<FileIdentifierInner>() as u8 * 8;
47
48 const DIRECTORY_FLAG: FileIdentifierInner = 1 << (Self::SIZE_BITS - 1);
49
50 /// Standard input file identifier (traditionally 0).
51 pub const STANDARD_IN: Self = Self::new_panic(1);
52
53 /// Standard output file identifier (traditionally 1).
54 pub const STANDARD_OUT: Self = Self::new_panic(2);
55
56 /// Standard error file identifier (traditionally 2).
57 pub const STANDARD_ERROR: Self = Self::new_panic(3);
58
59 /// Minimum file identifier available for regular files.
60 ///
61 /// Regular files should use identifiers starting from this value to avoid
62 /// conflicts with internal or reserved identifiers.
63 pub const MINIMUM_FILE: Self = Self::new_panic(4);
64
65 /// Maximum possible file identifier value.
66 pub const MAXIMUM_FILE: Self = Self::new_panic(Self::DIRECTORY_FLAG - 1);
67
68 pub const MINIMUM_DIRECTORY: Self = Self::new_panic(Self::DIRECTORY_FLAG);
69
70 pub const MAXIMUM_DIRECTORY: Self = Self::new_panic(FileIdentifierInner::MAX);
71 /// Create a new file identifier from a raw value.
72 ///
73 /// # Arguments
74 ///
75 /// * `Identifier` - The raw identifier value.
76 pub const fn new(identifier: u16) -> Option<Self> {
77 if let Some(non_zero) = NonZero::new(identifier) {
78 Some(Self(non_zero))
79 } else {
80 None
81 }
82 }
83
84 pub const fn new_panic(identifier: u16) -> Self {
85 Self::new(identifier).expect("FileIdentifier cannot be zero")
86 }
87
88 /// Get the raw identifier value.
89 ///
90 /// # Returns
91 ///
92 /// The underlying raw identifier value.
93 pub const fn into_inner(self) -> FileIdentifierInner {
94 self.0.get()
95 }
96
97 pub const fn into_unique(self, task: TaskIdentifier) -> UniqueFileIdentifier {
98 UniqueFileIdentifier::new(task, self)
99 }
100
101 pub const fn is_directory(self) -> bool {
102 (self.0.get() & Self::DIRECTORY_FLAG) != 0
103 }
104}
105
106impl TryFrom<FileIdentifierInner> for FileIdentifier {
107 type Error = virtual_file_system::Error;
108
109 fn try_from(value: u16) -> Result<Self, Self::Error> {
110 NonZero::new(value)
111 .map(FileIdentifier)
112 .ok_or(virtual_file_system::Error::InvalidIdentifier)
113 }
114}
115
116impl From<FileIdentifier> for u16 {
117 fn from(file_identifier: FileIdentifier) -> Self {
118 file_identifier.0.get()
119 }
120}