use crate::model::attempt_journal::OperationBindingRecord;
use thiserror::Error;
pub const MAX_CONTROLLERS: usize = 10;
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ControllerSet {
principals: Vec<String>,
}
impl ControllerSet {
pub fn new(mut principals: Vec<String>) -> Result<Self, ControlObservationError> {
if principals.len() > MAX_CONTROLLERS {
return Err(ControlObservationError::TooManyControllers);
}
for principal in &mut principals {
*principal = super::principal::canonical_text(principal)
.ok_or(ControlObservationError::InvalidPrincipal)?;
}
principals.sort();
if principals.windows(2).any(|pair| pair[0] == pair[1]) {
return Err(ControlObservationError::DuplicateController);
}
Ok(Self { principals })
}
#[must_use]
pub fn principals(&self) -> &[String] {
&self.principals
}
#[must_use]
pub fn contains_caller(&self, binding: &OperationBindingRecord) -> bool {
self.principals
.binary_search_by(|principal| principal.as_str().cmp(binding.caller()))
.is_ok()
}
}
#[derive(Debug, Eq, Error, PartialEq)]
pub enum ControlObservationError {
#[error("invalid control observation principal")]
InvalidPrincipal,
#[error("controller set exceeds {MAX_CONTROLLERS}")]
TooManyControllers,
#[error("duplicate controller principal")]
DuplicateController,
}
#[cfg(test)]
mod tests;