Skip to main content

datalog_structural_model/
capability.rs

1//! Finite sets of explicitly supported Datalog language features.
2use crate::{Aggregator, BindingKind, FilterKind};
3use std::collections::BTreeSet;
4
5/// A language feature required by a rule program.
6/// Positive flat atoms require no extension capabilities.
7#[derive(
8    Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize,
9)]
10pub enum DatalogFeature {
11    /// Stratified negation-as-failure.
12    StratifiedNegation,
13    /// Structured triple terms in rule arguments.
14    TripleTerms,
15    /// Deterministic head-only Skolem generation.
16    SkolemGeneration,
17    /// An exact built-in filter operation.
18    Filter(FilterKind),
19    /// An exact built-in binding operation.
20    Binding(BindingKind),
21    /// An exact aggregation operation.
22    Aggregate(Aggregator),
23}
24
25/// Language feature set. This describes a contract; it does not certify an engine.
26#[derive(Clone, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
27#[serde(transparent)]
28pub struct DatalogCapabilities(BTreeSet<DatalogFeature>);
29impl DatalogCapabilities {
30    /// Pure positive Datalog over flat terms, with no extension operations.
31    #[must_use]
32    pub fn positive() -> Self {
33        Self::default()
34    }
35    /// Declare one additional supported feature.
36    #[must_use]
37    pub fn with(mut self, feature: DatalogFeature) -> Self {
38        self.0.insert(feature);
39        self
40    }
41    /// Inspect one exact feature.
42    #[must_use]
43    pub fn contains(&self, feature: &DatalogFeature) -> bool {
44        self.0.contains(feature)
45    }
46    /// Inspect features in stable structural order.
47    pub fn iter(&self) -> impl Iterator<Item = &DatalogFeature> {
48        self.0.iter()
49    }
50    /// All features representable by this model, without claiming engine support.
51    #[must_use]
52    pub fn all_model_features() -> Self {
53        let mut result = Self::positive()
54            .with(DatalogFeature::StratifiedNegation)
55            .with(DatalogFeature::TripleTerms)
56            .with(DatalogFeature::SkolemGeneration);
57        for kind in FilterKind::ALL {
58            result.0.insert(DatalogFeature::Filter(*kind));
59        }
60        for kind in BindingKind::ALL {
61            result.0.insert(DatalogFeature::Binding(*kind));
62        }
63        for kind in [
64            Aggregator::Count,
65            Aggregator::Sum,
66            Aggregator::Min,
67            Aggregator::Max,
68            Aggregator::Avg,
69        ] {
70            result.0.insert(DatalogFeature::Aggregate(kind));
71        }
72        result
73    }
74    pub(crate) fn insert(&mut self, feature: DatalogFeature) {
75        self.0.insert(feature);
76    }
77    pub(crate) fn missing_from(&self, supported: &Self) -> Self {
78        Self(self.0.difference(&supported.0).copied().collect())
79    }
80    pub(crate) fn is_empty(&self) -> bool {
81        self.0.is_empty()
82    }
83}