use std::collections::BTreeMap;
use serde::{Deserialize, Deserializer, Serialize};
use crate::{Fact, FactId, GatekeepError, GatekeepResult};
pub type TraceValue = serde_json::Value;
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Presence {
Present,
Absent,
Unknown,
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
struct Facts(BTreeMap<FactId, (Presence, Option<TraceValue>)>);
impl Facts {
fn insert(&mut self, fact: FactId, presence: Presence, value: Option<TraceValue>) {
self.0.insert(fact, (presence, value));
}
fn presence(&self, fact: &FactId) -> Presence {
self.0
.get(fact)
.map_or(Presence::Absent, |(presence, _value)| *presence)
}
fn iter(&self) -> impl Iterator<Item = (&FactId, Presence)> {
self.0
.iter()
.map(|(fact, (presence, _value))| (fact, *presence))
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize)]
pub struct KnownFacts(Facts);
impl KnownFacts {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn from_entries(
entries: impl IntoIterator<Item = (FactId, Presence)>,
) -> GatekeepResult<Self> {
let mut facts = Facts::default();
for (fact, presence) in entries {
if presence == Presence::Unknown {
return Err(GatekeepError::InvalidPolicyRecord {
reason: "known facts cannot contain unknown presence",
});
}
facts.insert(fact, presence, None);
}
Ok(Self(facts))
}
pub(crate) fn from_known_entries(
entries: impl IntoIterator<Item = (FactId, Presence)>,
) -> Self {
let mut facts = Facts::default();
for (fact, presence) in entries {
if presence != Presence::Unknown {
facts.insert(fact, presence, None);
}
}
Self(facts)
}
#[must_use]
pub fn with_present<F: Fact>(mut self) -> Self {
self.0.insert(
FactId::from_trusted(F::ID.as_str()),
Presence::Present,
None,
);
self
}
#[must_use]
pub fn with_absent<F: Fact>(mut self) -> Self {
self.0
.insert(FactId::from_trusted(F::ID.as_str()), Presence::Absent, None);
self
}
pub fn try_with_fact(mut self, fact: FactId, presence: Presence) -> GatekeepResult<Self> {
if presence == Presence::Unknown {
return Err(GatekeepError::InvalidPolicyRecord {
reason: "known facts cannot contain unknown presence",
});
}
self.0.insert(fact, presence, None);
Ok(self)
}
#[must_use]
pub fn presence(&self, fact: &FactId) -> Presence {
self.0.presence(fact)
}
}
impl<'de> Deserialize<'de> for KnownFacts {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let facts = Facts::deserialize(deserializer)?;
for (_fact, presence) in facts.iter() {
if presence == Presence::Unknown {
return Err(serde::de::Error::custom(
"known facts cannot contain unknown presence",
));
}
}
Ok(Self(facts))
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct PartialFacts(Facts);
impl PartialFacts {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn from_entries(entries: impl IntoIterator<Item = (FactId, Presence)>) -> Self {
let mut facts = Facts::default();
for (fact, presence) in entries {
facts.insert(fact, presence, None);
}
Self(facts)
}
#[must_use]
pub fn with_present<F: Fact>(mut self) -> Self {
self.0.insert(
FactId::from_trusted(F::ID.as_str()),
Presence::Present,
None,
);
self
}
#[must_use]
pub fn with_absent<F: Fact>(mut self) -> Self {
self.0
.insert(FactId::from_trusted(F::ID.as_str()), Presence::Absent, None);
self
}
#[must_use]
pub fn with_unknown<F: Fact>(mut self) -> Self {
self.0.insert(
FactId::from_trusted(F::ID.as_str()),
Presence::Unknown,
None,
);
self
}
#[must_use]
pub fn with_fact(mut self, fact: FactId, presence: Presence) -> Self {
self.0.insert(fact, presence, None);
self
}
#[must_use]
pub fn presence(&self, fact: &FactId) -> Presence {
self.0.presence(fact)
}
pub(crate) fn known_entries(&self) -> impl Iterator<Item = (&FactId, Presence)> {
self.0
.iter()
.filter(|(_fact, presence)| *presence != Presence::Unknown)
}
}