use std::fmt;
use crate::{Aid, Value, Var};
pub trait AsBinding {
fn variables(&self) -> Vec<Var>;
fn binds(&self, variable: Var) -> Option<usize>;
fn required_to_extend(&self, prefix: &AsBinding, target: Var) -> Option<Option<Var>>;
fn ready_to_extend(&self, prefix: &AsBinding) -> Option<Var>;
fn can_extend(&self, prefix: &AsBinding, target: Var) -> bool {
self.ready_to_extend(prefix) == Some(target)
}
}
impl AsBinding for Vec<Var> {
fn variables(&self) -> Vec<Var> {
Vec::new()
}
fn binds(&self, variable: Var) -> Option<usize> {
self.iter().position(|&x| variable == x)
}
fn ready_to_extend(&self, _prefix: &AsBinding) -> Option<Var> {
None
}
fn required_to_extend(&self, _prefix: &AsBinding, _target: Var) -> Option<Option<Var>> {
Some(None)
}
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize)]
pub enum Binding {
Attribute(AttributeBinding),
Not(AntijoinBinding),
Constant(ConstantBinding),
BinaryPredicate(BinaryPredicateBinding),
}
impl Binding {
pub fn attribute(e: Var, name: &str, v: Var) -> Binding {
Binding::Attribute(AttributeBinding {
variables: (e, v),
source_attribute: name.to_string(),
})
}
pub fn constant(variable: Var, value: Value) -> Binding {
Binding::Constant(ConstantBinding { variable, value })
}
pub fn binary_predicate(predicate: BinaryPredicate, x: Var, y: Var) -> Binding {
Binding::BinaryPredicate(BinaryPredicateBinding {
variables: (x, y),
predicate,
})
}
pub fn not(binding: Binding) -> Binding {
Binding::Not(AntijoinBinding {
binding: Box::new(binding),
})
}
}
impl AsBinding for Binding {
fn variables(&self) -> Vec<Var> {
match *self {
Binding::Attribute(ref binding) => binding.variables(),
Binding::Not(ref binding) => binding.variables(),
Binding::Constant(ref binding) => binding.variables(),
Binding::BinaryPredicate(ref binding) => binding.variables(),
}
}
fn binds(&self, variable: Var) -> Option<usize> {
match *self {
Binding::Attribute(ref binding) => binding.binds(variable),
Binding::Not(ref binding) => binding.binds(variable),
Binding::Constant(ref binding) => binding.binds(variable),
Binding::BinaryPredicate(ref binding) => binding.binds(variable),
}
}
fn ready_to_extend(&self, prefix: &AsBinding) -> Option<Var> {
match *self {
Binding::Attribute(ref binding) => binding.ready_to_extend(prefix),
Binding::Not(ref binding) => binding.ready_to_extend(prefix),
Binding::Constant(ref binding) => binding.ready_to_extend(prefix),
Binding::BinaryPredicate(ref binding) => binding.ready_to_extend(prefix),
}
}
fn required_to_extend(&self, prefix: &AsBinding, target: Var) -> Option<Option<Var>> {
match *self {
Binding::Attribute(ref binding) => binding.required_to_extend(prefix, target),
Binding::Not(ref binding) => binding.required_to_extend(prefix, target),
Binding::Constant(ref binding) => binding.required_to_extend(prefix, target),
Binding::BinaryPredicate(ref binding) => binding.required_to_extend(prefix, target),
}
}
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct AttributeBinding {
pub variables: (Var, Var),
pub source_attribute: Aid,
}
impl AsBinding for AttributeBinding {
fn variables(&self) -> Vec<Var> {
vec![self.variables.0, self.variables.1]
}
fn binds(&self, variable: Var) -> Option<usize> {
if self.variables.0 == variable {
Some(0)
} else if self.variables.1 == variable {
Some(1)
} else {
None
}
}
fn ready_to_extend(&self, prefix: &AsBinding) -> Option<Var> {
if prefix.binds(self.variables.0).is_some() && prefix.binds(self.variables.1).is_none() {
Some(self.variables.1)
} else if prefix.binds(self.variables.1).is_some()
&& prefix.binds(self.variables.0).is_none()
{
Some(self.variables.0)
} else {
None
}
}
fn required_to_extend(&self, prefix: &AsBinding, target: Var) -> Option<Option<Var>> {
match self.binds(target) {
None => None,
Some(offset) => {
if offset == 0 {
assert!(prefix.binds(self.variables.0).is_none());
match prefix.binds(self.variables.1) {
None => Some(Some(self.variables.1)),
Some(_) => Some(None),
}
} else {
assert!(prefix.binds(self.variables.1).is_none());
match prefix.binds(self.variables.0) {
None => Some(Some(self.variables.0)),
Some(_) => Some(None),
}
}
}
}
}
}
impl fmt::Debug for AttributeBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"[{} {} {}]",
self.variables.0, self.source_attribute, self.variables.1
)
}
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct AntijoinBinding {
pub binding: Box<Binding>,
}
impl AsBinding for AntijoinBinding {
fn variables(&self) -> Vec<Var> {
self.binding.variables()
}
fn binds(&self, variable: Var) -> Option<usize> {
self.binding.binds(variable)
}
fn ready_to_extend(&self, prefix: &AsBinding) -> Option<Var> {
self.binding.ready_to_extend(prefix)
}
fn required_to_extend(&self, prefix: &AsBinding, target: Var) -> Option<Option<Var>> {
self.binding.required_to_extend(prefix, target)
}
}
impl fmt::Debug for AntijoinBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Not({:?})", self.binding)
}
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct ConstantBinding {
pub variable: Var,
pub value: Value,
}
impl AsBinding for ConstantBinding {
fn variables(&self) -> Vec<Var> {
vec![self.variable]
}
fn binds(&self, variable: Var) -> Option<usize> {
if self.variable == variable {
Some(0)
} else {
None
}
}
fn ready_to_extend(&self, prefix: &AsBinding) -> Option<Var> {
if prefix.binds(self.variable).is_none() {
Some(self.variable)
} else {
None
}
}
fn required_to_extend(&self, prefix: &AsBinding, target: Var) -> Option<Option<Var>> {
match self.binds(target) {
None => None,
Some(_) => match prefix.binds(target) {
None => Some(Some(self.variable)),
Some(_) => Some(None),
},
}
}
}
impl fmt::Debug for ConstantBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Constant({}, {:?})", self.variable, self.value)
}
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize)]
pub enum BinaryPredicate {
LT,
GT,
LTE,
GTE,
EQ,
NEQ,
}
#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Serialize, Deserialize)]
pub struct BinaryPredicateBinding {
pub variables: (Var, Var),
pub predicate: BinaryPredicate,
}
impl AsBinding for BinaryPredicateBinding {
fn variables(&self) -> Vec<Var> {
vec![self.variables.0, self.variables.1]
}
fn binds(&self, variable: Var) -> Option<usize> {
if self.variables.0 == variable {
Some(0)
} else if self.variables.1 == variable {
Some(1)
} else {
None
}
}
fn ready_to_extend(&self, prefix: &AsBinding) -> Option<Var> {
if prefix.binds(self.variables.0).is_some() && prefix.binds(self.variables.1).is_none() {
Some(self.variables.1)
} else if prefix.binds(self.variables.1).is_some()
&& prefix.binds(self.variables.0).is_none()
{
Some(self.variables.0)
} else {
None
}
}
fn required_to_extend(&self, prefix: &AsBinding, target: Var) -> Option<Option<Var>> {
match self.binds(target) {
None => None,
Some(offset) => {
if offset == 0 {
assert!(prefix.binds(self.variables.0).is_none());
match prefix.binds(self.variables.1) {
None => Some(Some(self.variables.1)),
Some(_) => Some(None),
}
} else {
assert!(prefix.binds(self.variables.1).is_none());
match prefix.binds(self.variables.0) {
None => Some(Some(self.variables.0)),
Some(_) => Some(None),
}
}
}
}
}
}
impl fmt::Debug for BinaryPredicateBinding {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"({:?} {} {})",
self.predicate, self.variables.0, self.variables.1
)
}
}