ruvix_types/
capability.rs1use crate::handle::Handle;
8use crate::object::ObjectType;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12#[repr(transparent)]
13pub struct CapHandle(pub Handle);
14
15impl CapHandle {
16 #[inline]
18 #[must_use]
19 pub const fn new(id: u32, generation: u32) -> Self {
20 Self(Handle::new(id, generation))
21 }
22
23 #[inline]
25 #[must_use]
26 pub const fn null() -> Self {
27 Self(Handle::null())
28 }
29
30 #[inline]
32 #[must_use]
33 pub const fn is_null(&self) -> bool {
34 self.0.is_null()
35 }
36
37 #[inline]
39 #[must_use]
40 pub const fn raw(&self) -> Handle {
41 self.0
42 }
43}
44
45impl Default for CapHandle {
46 fn default() -> Self {
47 Self::null()
48 }
49}
50
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56#[repr(transparent)]
57pub struct CapRights(u32);
58
59impl CapRights {
60 pub const READ: Self = Self(0b0000_0001);
62
63 pub const WRITE: Self = Self(0b0000_0010);
65
66 pub const GRANT: Self = Self(0b0000_0100);
68
69 pub const REVOKE: Self = Self(0b0000_1000);
71
72 pub const EXECUTE: Self = Self(0b0001_0000);
74
75 pub const PROVE: Self = Self(0b0010_0000);
78
79 pub const GRANT_ONCE: Self = Self(0b0100_0000);
82
83 pub const NONE: Self = Self(0);
85
86 pub const ALL: Self = Self(0b0111_1111);
88
89 #[inline]
91 #[must_use]
92 pub const fn from_bits(bits: u32) -> Self {
93 Self(bits)
94 }
95
96 #[inline]
98 #[must_use]
99 pub const fn bits(&self) -> u32 {
100 self.0
101 }
102
103 #[inline]
105 #[must_use]
106 pub const fn is_empty(&self) -> bool {
107 self.0 == 0
108 }
109
110 #[inline]
112 #[must_use]
113 pub const fn contains(&self, other: Self) -> bool {
114 (self.0 & other.0) == other.0
115 }
116
117 #[inline]
119 #[must_use]
120 pub const fn union(self, other: Self) -> Self {
121 Self(self.0 | other.0)
122 }
123
124 #[inline]
126 #[must_use]
127 pub const fn intersection(self, other: Self) -> Self {
128 Self(self.0 & other.0)
129 }
130
131 #[inline]
133 #[must_use]
134 pub const fn difference(self, other: Self) -> Self {
135 Self(self.0 & !other.0)
136 }
137
138 #[inline]
140 #[must_use]
141 pub const fn is_subset_of(&self, other: Self) -> bool {
142 (self.0 & other.0) == self.0
143 }
144}
145
146impl Default for CapRights {
147 fn default() -> Self {
148 Self::NONE
149 }
150}
151
152impl core::ops::BitOr for CapRights {
153 type Output = Self;
154
155 fn bitor(self, rhs: Self) -> Self::Output {
156 self.union(rhs)
157 }
158}
159
160impl core::ops::BitAnd for CapRights {
161 type Output = Self;
162
163 fn bitand(self, rhs: Self) -> Self::Output {
164 self.intersection(rhs)
165 }
166}
167
168impl core::ops::BitOrAssign for CapRights {
169 fn bitor_assign(&mut self, rhs: Self) {
170 self.0 |= rhs.0;
171 }
172}
173
174impl core::ops::BitAndAssign for CapRights {
175 fn bitand_assign(&mut self, rhs: Self) {
176 self.0 &= rhs.0;
177 }
178}
179
180#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187#[repr(C)]
188pub struct Capability {
189 pub object_id: u64,
191
192 pub object_type: ObjectType,
194
195 pub rights: CapRights,
197
198 pub badge: u64,
202
203 pub epoch: u64,
206}
207
208impl Capability {
209 #[inline]
211 #[must_use]
212 pub const fn new(
213 object_id: u64,
214 object_type: ObjectType,
215 rights: CapRights,
216 badge: u64,
217 epoch: u64,
218 ) -> Self {
219 Self {
220 object_id,
221 object_type,
222 rights,
223 badge,
224 epoch,
225 }
226 }
227
228 #[inline]
230 #[must_use]
231 pub const fn has_rights(&self, required: CapRights) -> bool {
232 self.rights.contains(required)
233 }
234
235 #[inline]
240 #[must_use]
241 pub fn derive(&self, new_rights: CapRights, new_badge: u64) -> Option<Self> {
242 if !self.has_rights(CapRights::GRANT) {
244 return None;
245 }
246
247 if !new_rights.is_subset_of(self.rights) {
249 return None;
250 }
251
252 let final_rights = if self.rights.contains(CapRights::GRANT_ONCE) {
254 new_rights.difference(CapRights::GRANT).difference(CapRights::GRANT_ONCE)
255 } else {
256 new_rights
257 };
258
259 Some(Self {
260 object_id: self.object_id,
261 object_type: self.object_type,
262 rights: final_rights,
263 badge: new_badge,
264 epoch: self.epoch,
265 })
266 }
267}
268
269#[cfg(test)]
270mod tests {
271 use super::*;
272
273 #[test]
274 fn test_cap_rights_operations() {
275 let rw = CapRights::READ | CapRights::WRITE;
276 assert!(rw.contains(CapRights::READ));
277 assert!(rw.contains(CapRights::WRITE));
278 assert!(!rw.contains(CapRights::GRANT));
279 }
280
281 #[test]
282 fn test_cap_rights_subset() {
283 let read = CapRights::READ;
284 let read_write = CapRights::READ | CapRights::WRITE;
285 assert!(read.is_subset_of(read_write));
286 assert!(!read_write.is_subset_of(read));
287 }
288
289 #[test]
290 fn test_capability_derive() {
291 let cap = Capability::new(
292 1,
293 ObjectType::Region,
294 CapRights::READ | CapRights::WRITE | CapRights::GRANT,
295 0,
296 1,
297 );
298
299 let derived = cap.derive(CapRights::READ, 42).unwrap();
301 assert_eq!(derived.rights, CapRights::READ);
302 assert_eq!(derived.badge, 42);
303 assert_eq!(derived.object_id, cap.object_id);
304 }
305
306 #[test]
307 fn test_capability_derive_fails_without_grant() {
308 let cap = Capability::new(1, ObjectType::Region, CapRights::READ, 0, 1);
309 assert!(cap.derive(CapRights::READ, 0).is_none());
310 }
311
312 #[test]
313 fn test_capability_derive_fails_with_more_rights() {
314 let cap = Capability::new(
315 1,
316 ObjectType::Region,
317 CapRights::READ | CapRights::GRANT,
318 0,
319 1,
320 );
321 assert!(cap.derive(CapRights::READ | CapRights::WRITE, 0).is_none());
322 }
323
324 #[test]
325 fn test_grant_once() {
326 let cap = Capability::new(
327 1,
328 ObjectType::Region,
329 CapRights::READ | CapRights::GRANT | CapRights::GRANT_ONCE,
330 0,
331 1,
332 );
333
334 let derived = cap.derive(CapRights::READ | CapRights::GRANT, 0).unwrap();
336 assert!(!derived.rights.contains(CapRights::GRANT));
337 }
338}