use gatekeep::{Fact, FactId, GatekeepError, SubjectSlot};
use keepsake::{RelationId, RelationSpec};
use thiserror::Error;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub enum QueryPresence {
#[default]
Resolve,
Defer,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FactBinding {
pub(crate) fact: FactId,
pub(crate) relation_id: RelationId,
pub(crate) subject_slot: Option<SubjectSlot>,
pub(crate) query_presence: QueryPresence,
}
impl FactBinding {
#[must_use]
pub const fn new(fact: FactId, relation_id: RelationId) -> Self {
Self::with_subject_and_query_presence(fact, relation_id, None, QueryPresence::Resolve)
}
#[must_use]
pub const fn with_query_presence(
fact: FactId,
relation_id: RelationId,
query_presence: QueryPresence,
) -> Self {
Self::with_subject_and_query_presence(fact, relation_id, None, query_presence)
}
#[must_use]
pub const fn on_subject(
fact: FactId,
relation_id: RelationId,
subject_slot: SubjectSlot,
) -> Self {
Self::with_subject_and_query_presence(
fact,
relation_id,
Some(subject_slot),
QueryPresence::Resolve,
)
}
#[must_use]
pub const fn with_subject_and_query_presence(
fact: FactId,
relation_id: RelationId,
subject_slot: Option<SubjectSlot>,
query_presence: QueryPresence,
) -> Self {
Self {
fact,
relation_id,
subject_slot,
query_presence,
}
}
pub fn for_relation_spec<F, R>() -> Result<Self, FactBindingError>
where
F: Fact,
R: RelationSpec,
{
Self::for_relation_spec_with_query_presence::<F, R>(QueryPresence::Resolve)
}
pub fn for_relation_spec_on_subject<F, R>(
subject_slot: SubjectSlot,
) -> Result<Self, FactBindingError>
where
F: Fact,
R: RelationSpec,
{
Self::for_relation_spec_on_subject_with_query_presence::<F, R>(
subject_slot,
QueryPresence::Resolve,
)
}
pub fn resolve_relation<F, R>() -> Result<Self, FactBindingError>
where
F: Fact,
R: RelationSpec,
{
Self::for_relation_spec_with_query_presence::<F, R>(QueryPresence::Resolve)
}
pub fn defer_relation<F, R>() -> Result<Self, FactBindingError>
where
F: Fact,
R: RelationSpec,
{
Self::for_relation_spec_with_query_presence::<F, R>(QueryPresence::Defer)
}
pub fn for_relation_spec_with_query_presence<F, R>(
query_presence: QueryPresence,
) -> Result<Self, FactBindingError>
where
F: Fact,
R: RelationSpec,
{
Ok(Self::with_query_presence(
F::ID.to_owned_id()?,
R::ID,
query_presence,
))
}
pub fn for_relation_spec_on_subject_with_query_presence<F, R>(
subject_slot: SubjectSlot,
query_presence: QueryPresence,
) -> Result<Self, FactBindingError>
where
F: Fact,
R: RelationSpec,
{
Ok(Self::with_subject_and_query_presence(
F::ID.to_owned_id()?,
R::ID,
Some(subject_slot),
query_presence,
))
}
#[must_use]
pub const fn fact(&self) -> &FactId {
&self.fact
}
#[must_use]
pub const fn relation_id(&self) -> RelationId {
self.relation_id
}
#[must_use]
pub const fn subject_slot(&self) -> Option<&SubjectSlot> {
self.subject_slot.as_ref()
}
#[must_use]
pub const fn query_presence(&self) -> QueryPresence {
self.query_presence
}
}
#[derive(Debug, Error, Clone, PartialEq, Eq)]
pub enum FactBindingError {
#[error(transparent)]
Gatekeep(#[from] GatekeepError),
}