1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// Copyright (C) 2020 - Will Glozer. All rights reserved.

use std::convert::TryFrom;
use std::ops::BitOr;
use super::Cap;

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Set(u64);

impl Set {
    pub fn empty() -> Self {
        Self(0)
    }

    pub fn clear(&mut self) {
        self.0 = 0;
    }

    pub fn contains<S: Into<Set>>(&self, set: S) -> bool {
        self.0 & set.into().0 != 0
    }

    pub fn insert<S: Into<Set>>(&mut self, set: S) {
        self.0 |= set.into().0
    }

    pub fn remove<S: Into<Set>>(&mut self, set: S) {
        self.0 &= !set.into().0;
    }

    pub fn shift(&self, high: &mut u32, low: &mut u32) {
        const MASK: u64 = 0xFFFFFFFF;
        *high = u32::try_from(self.0 >> 32 & MASK).unwrap_or(0);
        *low  = u32::try_from(self.0       & MASK).unwrap_or(0);
    }
}

impl BitOr for Cap {
    type Output = Set;

    fn bitor(self, rhs: Self) -> Set {
        let x = u64::from(self);
        let y = u64::from(rhs);
        Set(x | y)
    }
}

impl BitOr<Cap> for Set {
    type Output = Set;

    fn bitor(self, rhs: Cap) -> Set {
        let x = self.0;
        let y = u64::from(rhs);
        Self(x | y)
    }
}

impl From<Cap> for Set {
    fn from(cap: Cap) -> Self {
        Self(u64::from(cap))
    }
}

impl From<(u32, u32)> for Set {
    fn from((high, low): (u32, u32)) -> Self {
        let x = u64::from(high) << 32;
        let y = u64::from(low);
        Self(x | y)
    }
}

#[test]
fn test() {
    use crate::caps::*;

    let mut set = Set::empty();
    set.insert(Chown);
    set.insert(Lease | Mknod);

    assert!(set.contains(Chown));
    assert!(set.contains(Chown | Lease | Mknod));
    assert!(!set.contains(Syslog));

    set.remove(Lease);
    assert!(!set.contains(Lease));
    assert!(set.contains(Chown | Mknod));

    set.clear();
    assert_eq!(Set::empty(), set);
}