use std::collections::BTreeMap;
use crate::errors::SpaceError;
use crate::spaces::composite::{conform_dict, conform_tuple};
use crate::spaces::fundamental::{
conform_box, conform_text, contains_discrete, contains_multibinary, contains_multidiscrete,
};
use crate::spaces::{SpaceSpec, SpaceType};
use crate::tensor::Tensor;
#[derive(Debug, Clone, PartialEq)]
pub enum SpaceValue {
Box(Tensor),
Discrete(i64),
MultiBinary(Vec<bool>),
MultiDiscrete(Vec<i64>),
Text(String),
Dict(BTreeMap<String, SpaceValue>),
Tuple(Vec<SpaceValue>),
}
#[derive(Debug)]
pub enum Conformance {
Ok,
Structural(SpaceError),
Range(SpaceError),
}
impl Conformance {
#[must_use]
pub fn is_ok(&self) -> bool {
matches!(self, Conformance::Ok)
}
fn into_result(self) -> Result<(), SpaceError> {
match self {
Conformance::Ok => Ok(()),
Conformance::Structural(err) | Conformance::Range(err) => Err(err),
}
}
}
pub fn contains(space: &SpaceSpec, value: &SpaceValue) -> Result<(), SpaceError> {
conform(space, value).into_result()
}
pub fn conform(space: &SpaceSpec, value: &SpaceValue) -> Conformance {
conform_at(space, value, "$")
}
pub(crate) fn conform_at(space: &SpaceSpec, value: &SpaceValue, path: &str) -> Conformance {
match space.space_type() {
SpaceType::Box => conform_box(space, value, path),
SpaceType::Discrete => structural(contains_discrete(space, value, path)),
SpaceType::MultiBinary => structural(contains_multibinary(space, value, path)),
SpaceType::MultiDiscrete => structural(contains_multidiscrete(space, value, path)),
SpaceType::Text => conform_text(space, value, path),
SpaceType::Dict => conform_dict(space, value, path),
SpaceType::Tuple => conform_tuple(space, value, path),
SpaceType::Unspecified => {
Conformance::Structural(SpaceError::invalid(path, "space type not specified"))
}
}
}
fn structural(result: Result<(), SpaceError>) -> Conformance {
match result {
Ok(()) => Conformance::Ok,
Err(err) => Conformance::Structural(err),
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ValidationPolicy {
#[default]
Warn,
Strict,
Off,
}
#[derive(Debug)]
pub enum PolicyOutcome {
Accept,
Warn(SpaceError),
Reject(SpaceError),
}
impl ValidationPolicy {
#[must_use]
pub fn evaluate(self, conformance: Conformance) -> PolicyOutcome {
match conformance {
Conformance::Ok => PolicyOutcome::Accept,
Conformance::Structural(err) => PolicyOutcome::Reject(err),
Conformance::Range(err) => match self {
ValidationPolicy::Warn => PolicyOutcome::Warn(err),
ValidationPolicy::Strict => PolicyOutcome::Reject(err),
ValidationPolicy::Off => PolicyOutcome::Accept,
},
}
}
#[must_use]
pub fn check(self, space: &SpaceSpec, value: &SpaceValue) -> PolicyOutcome {
self.evaluate(conform(space, value))
}
}