138 lines
3.4 KiB
Rust
138 lines
3.4 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",
|
|
}
|
|
|
|
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);
|
|
|
|
/// 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)
|
|
}
|
|
}
|