use crate::{DatalogCapabilities, DatalogFeature, EqualityMode, Program, ProgramValidationError};
use std::{error::Error, fmt};
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct DatalogProfile {
capabilities: DatalogCapabilities,
equality_mode: EqualityMode,
}
impl DatalogProfile {
#[must_use]
pub fn new(capabilities: DatalogCapabilities, equality_mode: EqualityMode) -> Self {
Self {
capabilities,
equality_mode,
}
}
#[must_use]
pub fn positive() -> Self {
Self::new(DatalogCapabilities::positive(), EqualityMode::Default)
}
#[must_use]
pub fn stratified() -> Self {
Self::new(
DatalogCapabilities::positive().with(DatalogFeature::StratifiedNegation),
EqualityMode::Default,
)
}
#[must_use]
pub fn capabilities(&self) -> &DatalogCapabilities {
&self.capabilities
}
#[must_use]
pub fn equality_mode(&self) -> EqualityMode {
self.equality_mode
}
}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub struct UnsupportedCapabilities {
missing: DatalogCapabilities,
}
impl UnsupportedCapabilities {
#[must_use]
pub fn missing(&self) -> &DatalogCapabilities {
&self.missing
}
}
impl fmt::Display for UnsupportedCapabilities {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "unsupported Datalog features: {:?}", self.missing)
}
}
impl Error for UnsupportedCapabilities {}
#[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize)]
#[serde(deny_unknown_fields)]
pub enum ProfileCheckError {
InvalidProgram(ProgramValidationError),
Unsupported(UnsupportedCapabilities),
}
impl fmt::Display for ProfileCheckError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidProgram(error) => error.fmt(f),
Self::Unsupported(error) => error.fmt(f),
}
}
}
impl Error for ProfileCheckError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::InvalidProgram(error) => Some(error),
Self::Unsupported(error) => Some(error),
}
}
}
impl Program {
pub fn validate_for(&self, profile: &DatalogProfile) -> Result<(), ProfileCheckError> {
self.validate_with_equality_mode(profile.equality_mode)
.map_err(ProfileCheckError::InvalidProgram)?;
let missing = self
.required_capabilities()
.missing_from(&profile.capabilities);
if !missing.is_empty() {
return Err(ProfileCheckError::Unsupported(UnsupportedCapabilities {
missing,
}));
}
Ok(())
}
}