Files
k-os/crates/manifest/src/capability.rs

148 lines
4.0 KiB
Rust

//! What an app can ask for: one name per app-facing server in the
//! catalog (see the vision's Servers note). Whether this device has the
//! server is a separate question, asked when an app is installed.
macro_rules! catalog {
($($variant:ident = $name:literal,)*) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Capability {
$($variant,)*
}
impl Capability {
pub const ALL: &[Capability] = &[$(Capability::$variant,)*];
pub fn from_name(name: &str) -> Option<Self> {
match name {
$($name => Some(Capability::$variant),)*
_ => None,
}
}
/// Its place in the catalog, as sent in a message word.
pub fn index(self) -> usize {
self as usize
}
pub fn from_index(i: usize) -> Option<Self> {
Capability::ALL.get(i).copied()
}
pub fn name(self) -> &'static str {
match self {
$(Capability::$variant => $name,)*
}
}
}
};
}
catalog! {
Display = "display",
Storage = "storage",
AudioPlayback = "audio_playback",
AudioCapture = "audio_capture",
Camera = "camera",
Network = "network",
Telephony = "telephony",
Bluetooth = "bluetooth",
Gps = "gps",
Usb = "usb",
Power = "power",
Notifications = "notifications",
Clipboard = "clipboard",
Contacts = "contacts",
Calendar = "calendar",
Alarms = "alarms",
MediaIndex = "media_index",
Keychain = "keychain",
Sync = "sync",
Accessibility = "accessibility",
Print = "print",
// System-only (see `Capabilities::SYSTEM_ONLY`).
Permissions = "permissions",
Session = "session",
Launch = "launch",
}
impl Capability {
fn bit(self) -> u32 {
1 << (self as u32)
}
}
/// A set of capabilities.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Capabilities(u32);
impl Capabilities {
pub const NONE: Self = Self(0);
/// Only apps on the system image may hold these, pre-approved by
/// whoever built it; an app a user installs that asks for one is
/// refused, so no prompt can talk a user into handing them over.
/// `permissions`: changing what other apps may use. `session`: who is
/// signed in, and signing out.
pub const SYSTEM_ONLY: Self = Self(1 << Capability::Permissions as u32 | 1 << Capability::Session as u32 | 1 << Capability::Launch as u32);
/// As sent in a message word.
pub const fn bits(self) -> u32 {
self.0
}
/// From a message word; bits past the catalog are dropped.
pub fn from_bits(bits: u32) -> Self {
Capability::ALL
.iter()
.copied()
.filter(|c| bits & c.bit() != 0)
.collect()
}
pub fn with(self, c: Capability) -> Self {
Self(self.0 | c.bit())
}
pub fn without(self, c: Capability) -> Self {
Self(self.0 & !c.bit())
}
pub fn contains(self, c: Capability) -> bool {
self.0 & c.bit() != 0
}
pub fn union(self, other: Self) -> Self {
Self(self.0 | other.0)
}
pub fn intersect(self, other: Self) -> Self {
Self(self.0 & other.0)
}
pub fn is_empty(self) -> bool {
self.0 == 0
}
/// Those in `self` but not in `other`.
pub fn minus(self, other: Self) -> Self {
Self(self.0 & !other.0)
}
/// Whether every capability in `self` is in `other`.
pub fn is_subset(self, other: Self) -> bool {
self.0 & !other.0 == 0
}
pub fn iter(self) -> impl Iterator<Item = Capability> {
Capability::ALL
.iter()
.copied()
.filter(move |c| self.contains(*c))
}
}
impl FromIterator<Capability> for Capabilities {
fn from_iter<I: IntoIterator<Item = Capability>>(iter: I) -> Self {
iter.into_iter().fold(Self::NONE, Self::with)
}
}