use crate::internal;
use pyo3::prelude::*;
use pyo3::{PyNumberProtocol, PyObjectProtocol};
use std::fmt;
use std::sync::Arc;
use std::vec;
pub trait ToInternal {
fn to_internal(&self) -> internal::Primitive;
fn display(&self) -> String;
}
#[pyclass]
#[derive(Clone)]
pub struct Construct {
pub contents: InterTree,
}
#[pyproto]
impl PyObjectProtocol for Construct {
fn __str__(self) -> PyResult<String> {
Ok(self.contents.display())
}
}
#[pyclass]
#[derive(Clone)]
pub struct Primitive {
pub obj: Arc<dyn ToInternal>,
}
impl Primitive {
pub fn extract(self) -> internal::Interaction {
self.obj.to_internal().wrap()
}
pub fn wrap(self) -> Construct {
InterTree::Item(self).wrap()
}
pub fn display(&self) -> String {
self.obj.display()
}
}
#[derive(Copy, Clone)]
pub enum Interaction {
Inter,
Diff,
Union,
}
impl fmt::Display for Interaction {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Self::Inter => write!(f, "&"),
Self::Union => write!(f, "|"),
Self::Diff => write!(f, "-"),
}
}
}
#[derive(Clone)]
pub enum InterTree {
Item(Primitive),
Node(Interaction, Box<InterTree>, Box<InterTree>),
}
impl InterTree {
pub fn wrap(self) -> Construct {
Construct { contents: self }
}
pub fn inter(self, other: Self) -> Self {
Self::Node(Interaction::Inter, Box::new(self), Box::new(other))
}
pub fn diff(self, other: Self) -> Self {
Self::Node(Interaction::Diff, Box::new(self), Box::new(other))
}
pub fn union(self, other: Self) -> Self {
Self::Node(Interaction::Union, Box::new(self), Box::new(other))
}
pub fn canonical(&self) -> vec::Vec<internal::Interaction> {
match self {
Self::Item(p) => vec![p.clone().extract()],
Self::Node(inter, a, b) => {
let a_can = a.canonical();
let b_can = b.canonical();
match inter {
Interaction::Union => vec_union(&a_can, &b_can),
Interaction::Inter => {
let mut res = vec::Vec::new();
for x in &a_can {
for y in &b_can {
let internal::Interaction(x_in, x_out) = x;
let internal::Interaction(y_in, y_out) = y;
res.push(internal::Interaction(
vec_union(x_in, y_in),
vec_union(x_out, y_out),
));
}
}
res
}
Interaction::Diff => {
let mut res = a_can;
for y in b_can {
let acc = res;
res = vec::Vec::new();
for x in acc {
let internal::Interaction(x_in, x_out) = &x;
let internal::Interaction(y_in, y_out) = &y;
for z in y_in {
res.push(internal::Interaction(
x_in.to_vec(),
vec_union(&x_out, &[z.clone()]),
));
}
if !y_out.is_empty() {
res.push(internal::Interaction(
vec_union(&x_in, &y_out),
x_out.to_vec(),
));
}
}
}
res
}
}
}
}
}
pub fn display(&self) -> String {
match self {
Self::Item(p) => p.display(),
Self::Node(_, lt, rt) => {
let s = String::from("Interaction of:");
let s = lt.accumulate_display(s);
rt.accumulate_display(s)
}
}
}
fn accumulate_display(&self, s: String) -> String {
match self {
Self::Item(p) => format!("{}\n {}", s, p.display()),
Self::Node(_, lt, rt) => {
let s = lt.accumulate_display(s);
rt.accumulate_display(s)
}
}
}
}
fn vec_union<T: Clone>(a: &[T], b: &[T]) -> vec::Vec<T> {
let mut res = vec::Vec::new();
for x in a {
res.push(x.clone());
}
for x in b {
res.push(x.clone());
}
res
}
#[pymethods]
impl Construct {
pub fn inter(&self, other: &Construct) -> Self {
Self {
contents: self.contents.clone().inter(other.contents.clone()),
}
}
pub fn union(&self, other: &Construct) -> Self {
Self {
contents: self.contents.clone().union(other.contents.clone()),
}
}
pub fn diff(&self, other: &Construct) -> Self {
Self {
contents: self.contents.clone().diff(other.contents.clone()),
}
}
}
#[pyproto]
impl PyNumberProtocol for Construct {
fn __and__(lhs: Construct, rhs: Construct) -> PyResult<Construct> {
Ok(lhs.inter(&rhs))
}
fn __or__(lhs: Construct, rhs: Construct) -> PyResult<Construct> {
Ok(lhs.union(&rhs))
}
fn __sub__(lhs: Construct, rhs: Construct) -> PyResult<Construct> {
Ok(lhs.diff(&rhs))
}
}