//! 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 { 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 { 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 { Capability::ALL .iter() .copied() .filter(move |c| self.contains(*c)) } } impl FromIterator for Capabilities { fn from_iter>(iter: I) -> Self { iter.into_iter().fold(Self::NONE, Self::with) } }