//! The owner's decision about one app: what it was granted. use crate::Error; use crate::capability::{Capabilities, Capability}; use crate::toml; #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] pub struct Decision { pub granted: Capabilities, } /// Longest decision file `write` produces: the header and every name. pub const MAX_TEXT: usize = 512; impl Decision { pub fn parse(text: &str) -> Result { let mut granted = None; toml::parse(text, |e| match (e.table, e.key) { ("decision", "granted") if granted.is_none() => { granted = Some(crate::manifest::capabilities(e.value, e.line)?); Ok(()) } ("decision", "granted") => Err(Error::Duplicate { line: e.line }), _ => Err(Error::Unknown { line: e.line }), })?; Ok(Self { granted: granted.ok_or(Error::Missing("granted"))?, }) } /// The file this decision is stored as, in `out`; its length. pub fn write(&self, out: &mut [u8; MAX_TEXT]) -> usize { let mut w = Writer { out, len: 0 }; w.put("[decision]\ngranted = ["); for (i, c) in self.granted.iter().enumerate() { if i > 0 { w.put(", "); } w.put("\""); w.put(Capability::name(c)); w.put("\""); } w.put("]\n"); w.len } } struct Writer<'a> { out: &'a mut [u8; MAX_TEXT], len: usize, } impl Writer<'_> { fn put(&mut self, s: &str) { let end = (self.len + s.len()).min(MAX_TEXT); self.out[self.len..end].copy_from_slice(&s.as_bytes()[..end - self.len]); self.len = end; } }