feat(manifest): app manifest + decision crate (strict TOML subset, checked newtypes, capability catalog); docs/apps.md spec

This commit is contained in:
2026-10-27 22:32:40 +01:00
parent ec3bc0d2a1
commit 9bc31a9bbe
11 changed files with 1016 additions and 0 deletions

View File

@@ -0,0 +1,109 @@
//! 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,
}
}
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);
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
}
/// 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)
}
}