mapped_file/
flags.rs

1//! All flags for controlling a `MappedFile<T>`.
2use super::*;
3use libc::c_int;
4
5/// Permissions for the mapped pages.
6#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)]
7pub enum Perm
8{
9#[default]
10    ReadWrite,
11    Readonly,
12    Writeonly,
13    RX,
14    WRX,
15}
16
17/// Flags for mapping a file descriptor.
18#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)]
19pub enum Flags
20{
21#[default]
22    Shared,
23    Private,
24}
25
26impl Flags
27{
28    /// Add these flags to another `MapFlags` provider's mask.
29    ///
30    /// # Safety
31    /// The caller *should* ensure there are no conflicting flags present in the bitwise OR of `self` and `flags`'s respective masks; if there are, then `mmap()` may fail. This will not result in unexpected mapping behaviour, but will cause an error.
32    ///
33    /// However, the caller **must** ensure there are no *overlapping* bits in the resulting mask, as that may produce a valid but unexpected combined mask.
34    ///
35    /// # `hugetlb` support
36    /// For adding huge-page mapping flags to these, use `with_hugetlb()` instead.
37    #[inline] 
38    pub unsafe fn chain_with(self, flags: impl MapFlags) -> impl MapFlags
39    {
40	struct Chained<T: ?Sized>(Flags, T);
41
42	unsafe impl<T: ?Sized> MapFlags for Chained<T>
43	where T: MapFlags
44	{
45	    #[inline(always)] 
46	    fn get_mmap_flags(&self) -> c_int {
47		self.0.get_flags() | self.1.get_mmap_flags()
48	    }
49	}
50
51	Chained(self, flags)
52    }
53    /// Add huge-page info to the mapping flags for this `MappedFile<T>` instance.
54    ///
55    /// # Returns
56    /// An opaque type that combines the flags of `self` with those computed by `hugetlb`.
57    #[inline] 
58    pub const fn with_hugetlb(self, hugetlb: HugePage) -> impl MapFlags + Send + Sync + 'static
59    {
60	#[derive(Debug)]
61	struct HugeTLBFlags(Flags, HugePage);
62	unsafe impl MapFlags for HugeTLBFlags
63	{
64	    #[inline(always)]
65	    fn get_mmap_flags(&self) -> c_int {
66		self.0.get_flags() | self.1.compute_huge().map(MapHugeFlag::get_mask).unwrap_or(0)
67	    }
68	}
69
70	HugeTLBFlags(self, hugetlb)
71    }
72}
73
74/// Any type implementing this trait can be passed to `MappedFile<T>`'s `try_/new()` method to provide flags directly for `mmap()`.
75/// Usually, the enum `Flags` should be used for this, but for HUGETLB configurations, or used-defined `MAP_FIXED` usages, it can be used on other types.
76///
77/// This trait is also implemented on `()`, which will just return `Flags::default()`'s implementation of it.
78///
79/// # Safety
80/// This trait is marked `unsafe` as invalid memory mapping configurations can cause invalid or undefined behaviour that is unknown to `MappedFile<T>`.
81pub unsafe trait MapFlags
82{
83    fn get_mmap_flags(&self) -> c_int;
84}
85
86unsafe impl MapFlags for ()
87{
88    #[inline]
89    fn get_mmap_flags(&self) -> c_int {
90	Flags::default().get_flags()
91    }
92}
93
94unsafe impl MapFlags for Flags
95{
96    #[inline(always)]
97    fn get_mmap_flags(&self) -> c_int {
98	self.get_flags()
99    }
100}
101
102impl Flags
103{
104#[inline(always)]
105    pub(super) const fn get_flags(self) -> c_int
106    {
107        use libc::{
108            MAP_SHARED,
109            MAP_PRIVATE,
110        };
111        match self {
112            Self::Shared => MAP_SHARED,
113            Self::Private => MAP_PRIVATE,
114        }
115    }
116#[inline(always)]
117    pub(super) const fn requires_write_access(&self) -> bool
118    {
119        match self {
120            Self::Shared => true,
121            _ => false
122        }
123    }
124}
125
126impl Perm
127{
128#[inline(always)]
129    pub(super) const fn get_prot(self) -> c_int
130    {
131        use libc::{
132            PROT_READ, PROT_WRITE, PROT_EXEC,
133        };
134        match self {
135            Self::ReadWrite => PROT_READ | PROT_WRITE,
136            Self::Readonly => PROT_READ,
137            Self::Writeonly => PROT_WRITE,
138            Self::RX => PROT_READ | PROT_EXEC,
139            Self::WRX => PROT_READ | PROT_WRITE | PROT_EXEC,
140        }
141    }
142#[inline(always)]
143    pub(super) const fn open_rw(&self, flags: Flags) -> (bool, bool)
144    {
145        let wr = flags.requires_write_access();
146        match self {
147            Self::ReadWrite | Self::WRX => (true, wr),
148            Self::Readonly | Self::RX => (true, false),
149            Self::Writeonly => (false, wr),
150        }
151    }
152}
153
154/// Options for flushing a mapping. These will control how the `msync()` is called.
155#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)]
156pub enum Flush
157{
158#[default]
159    Wait,
160    Async,
161    Invalidate,
162    InvalidateAsync,
163}
164
165impl Flush
166{
167#[inline(always)]
168    pub(super) const fn get_ms(self) -> c_int
169    {
170        use libc::{
171            MS_SYNC, MS_ASYNC,
172            MS_INVALIDATE,
173        };
174        match self {
175            Self::Wait => MS_SYNC,
176            Self::Async => MS_ASYNC,
177            Self::Invalidate => MS_SYNC | MS_INVALIDATE,
178            Self::InvalidateAsync => MS_ASYNC | MS_INVALIDATE,
179        }
180    }
181}
182
183/// Advice to the kernel about how to load the mapped pages. These will control `madvise()`.
184#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Copy, Default)]
185pub enum Advice {
186#[default]
187    Normal,
188    Sequential,
189    RandomAccess,
190}
191
192impl Advice
193{
194#[inline(always)]
195    pub(crate) const fn get_madv(self) -> c_int
196    {
197        use libc::{
198            MADV_NORMAL,
199            MADV_SEQUENTIAL,
200            MADV_RANDOM,
201        };
202        match self {
203            Self::Normal => MADV_NORMAL,
204            Self::Sequential => MADV_SEQUENTIAL,
205            Self::RandomAccess => MADV_RANDOM,
206        }
207    }
208}