#![allow(clippy::module_name_repetitions)]
use std::{
collections::{BinaryHeap, HashMap},
fmt::{Debug, Display},
};
use serde::{Deserialize, Serialize};
use super::attribute::Attribute;
use crate::error::Error;
#[derive(Clone, Deserialize)]
pub struct PolicyAxis {
name: String,
attributes: Vec<String>,
hierarchical: bool,
}
impl PolicyAxis {
#[must_use]
pub fn new(name: &str, attributes: &[&str], hierarchical: bool) -> Self {
Self {
name: name.to_owned(),
attributes: attributes.iter().map(|s| (*s).to_string()).collect(),
hierarchical,
}
}
#[allow(clippy::len_without_is_empty)]
#[must_use]
pub fn len(&self) -> usize {
self.attributes.len()
}
pub fn attributes(&self) -> &[String] {
&self.attributes
}
pub fn name(&self) -> &str {
&self.name
}
pub fn is_hierarchical(&self) -> bool {
self.hierarchical
}
}
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Policy {
pub last_attribute_value: u32,
pub max_attribute_value: u32,
pub store: HashMap<String, (Vec<String>, bool)>,
pub attribute_to_int: HashMap<Attribute, BinaryHeap<u32>>,
}
impl Display for Policy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let json = serde_json::to_string(&self);
match json {
Ok(string) => write!(f, "{}", string),
Err(err) => write!(f, "{}", err),
}
}
}
impl Policy {
#[must_use]
pub fn new(nb_revocation: u32) -> Self {
Self {
last_attribute_value: 0,
max_attribute_value: nb_revocation,
store: HashMap::new(),
attribute_to_int: HashMap::new(),
}
}
pub fn as_map(&self) -> &HashMap<String, (Vec<String>, bool)> {
&self.store
}
#[must_use]
pub fn max_attr(&self) -> u32 {
self.max_attribute_value
}
pub fn add_axis(&mut self, axis: &PolicyAxis) -> Result<(), Error> {
if axis.len() > u32::MAX as usize {
return Err(Error::CapacityOverflow);
}
if (axis.len() as u32) + self.last_attribute_value > self.max_attribute_value {
return Err(Error::CapacityOverflow);
}
if self.store.contains_key(&axis.name) {
return Err(Error::ExistingPolicy(axis.name.clone()));
} else {
self.store.insert(
axis.name.clone(),
(axis.attributes.clone(), axis.hierarchical),
);
}
for attr in &axis.attributes {
self.last_attribute_value += 1;
if self
.attribute_to_int
.insert(
(axis.name.clone(), attr.clone()).into(),
vec![self.last_attribute_value].into(),
)
.is_some()
{
return Err(Error::ExistingPolicy(axis.name.clone()));
}
}
Ok(())
}
pub fn rotate(&mut self, attr: &Attribute) -> Result<(), Error> {
if self.last_attribute_value == self.max_attribute_value {
Err(Error::CapacityOverflow)
} else if let Some(heap) = self.attribute_to_int.get_mut(attr) {
self.last_attribute_value += 1;
heap.push(self.last_attribute_value);
Ok(())
} else {
Err(Error::AttributeNotFound(format!("{:?}", attr)))
}
}
pub fn attributes(&self) -> Vec<Attribute> {
self.attribute_to_int
.keys()
.cloned()
.collect::<Vec<Attribute>>()
}
pub fn attribute_values(&self, attribute: &Attribute) -> Result<Vec<u32>, Error> {
let mut v = self
.attribute_to_int
.get(attribute)
.cloned()
.ok_or_else(|| Error::AttributeNotFound(attribute.to_string()))?
.into_sorted_vec();
v.reverse();
Ok(v)
}
pub fn attribute_current_value(&self, attribute: &Attribute) -> Result<u32, Error> {
let values = self.attribute_values(attribute)?;
values
.first()
.ok_or_else(|| {
Error::InvalidAttribute(format!(
"the attribute {} does not have any value!",
attribute
))
})
.cloned()
}
pub fn attributes_values(&self, attributes: &[Attribute]) -> Result<Vec<u32>, Error> {
let mut values: Vec<u32> = Vec::with_capacity(attributes.len());
for att in attributes {
let v = self
.attribute_to_int
.get(att)
.and_then(std::collections::BinaryHeap::peek)
.ok_or_else(|| Error::AttributeNotFound(format!("{:?}", att)))?;
values.push(*v);
}
Ok(values)
}
}