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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//! Provide basic [capability-based security].
//!
//! The wrapper type [`WithCap`] associates a **capability** to an object, that
//! is a set of access rights. When accessing the object, we must explicitly
//! specify the access capability, and it must not violate the capability
//! associated with the object at initialization.
//!
//! # Examples
//!
//! ```
//! use capability::{Cap, WithCap};
//!
//! let data = WithCap::new(42, Cap::READ | Cap::WRITE);
//!
//! // Access with the correct capability.
//! assert_eq!(data.access(Cap::READ).unwrap(), &42);
//! assert_eq!(data.access(Cap::WRITE).unwrap(), &42);
//! assert_eq!(data.access(Cap::READ | Cap::WRITE).unwrap(), &42);
//!
//! // Access with the incorrect capability.
//! assert!(data.access(Cap::EXECUTE).is_err());
//! assert!(data.access(Cap::READ | Cap::EXECUTE).is_err());
//! ```
//!
//! [capability-based security]:
//!     https://en.wikipedia.org/wiki/Capability-based_security
//!

#![no_std]

bitflags::bitflags! {
    /// Capabilities (access rights).
    #[derive(Default, Debug, Clone, Copy)]
    pub struct Cap: u32 {
        /// Readable access.
        const READ = 1 << 0;
        /// Writable access.
        const WRITE = 1 << 1;
        /// Executable access.
        const EXECUTE = 1 << 2;
    }
}

/// Error type for capability violation.
#[derive(Debug, Default, Eq, PartialEq)]
#[non_exhaustive]
pub struct CapError;

/// A wrapper that holds a type with a capability.
#[derive(Clone)]
pub struct WithCap<T> {
    inner: T,
    cap: Cap,
}

impl<T> WithCap<T> {
    /// Create a new instance with the given capability.
    pub fn new(inner: T, cap: Cap) -> Self {
        Self { inner, cap }
    }

    /// Get the capability.
    pub const fn cap(&self) -> Cap {
        self.cap
    }

    /// Check if the inner data can be accessed with the given capability.
    ///
    /// # Examples
    ///
    /// ```
    /// use capability::{Cap, WithCap};
    ///
    /// let data = WithCap::new(42, Cap::READ);
    ///
    /// assert!(data.can_access(Cap::READ));
    /// assert!(!data.can_access(Cap::WRITE));
    /// ```
    pub const fn can_access(&self, cap: Cap) -> bool {
        self.cap.contains(cap)
    }

    /// Access the inner value without capability check.
    ///
    /// # Safety
    ///
    /// Caller must ensure not to violate the capability.
    pub unsafe fn access_unchecked(&self) -> &T {
        &self.inner
    }

    /// Access the inner value with the given capability, or return `CapError`
    /// if cannot access.
    ///
    /// # Examples
    ///
    /// ```
    /// use capability::{Cap, CapError, WithCap};
    ///
    /// let data = WithCap::new(42, Cap::READ);
    ///
    /// assert_eq!(data.access(Cap::READ).unwrap(), &42);
    /// assert_eq!(data.access(Cap::WRITE).err(), Some(CapError::default()));
    /// ```
    pub const fn access(&self, cap: Cap) -> Result<&T, CapError> {
        if self.can_access(cap) {
            Ok(&self.inner)
        } else {
            Err(CapError)
        }
    }

    /// Access the inner value with the given capability, or return the given
    /// `err` if cannot access.
    ///
    /// # Examples
    ///
    /// ```
    /// use capability::{Cap, WithCap};
    ///
    /// let data = WithCap::new(42, Cap::READ);
    ///
    /// assert_eq!(data.access_or_err(Cap::READ, "cannot read").unwrap(), &42);
    /// assert_eq!(data.access_or_err(Cap::WRITE, "cannot write").err(), Some("cannot write"));
    /// ```
    pub fn access_or_err<E>(&self, cap: Cap, err: E) -> Result<&T, E> {
        if self.can_access(cap) {
            Ok(&self.inner)
        } else {
            Err(err)
        }
    }
}

impl From<CapError> for axerrno::AxError {
    #[inline]
    fn from(_: CapError) -> Self {
        Self::PermissionDenied
    }
}