use std::fmt;
use std::sync::Arc;
use crate::node::{
CoreConstructible, DisconnectConstructible, JetConstructible, NoDisconnect,
WitnessConstructible,
};
use crate::types::{Bound, Error, Final, Type};
use crate::{jet::Jet, Value};
use super::variable::new_name;
#[derive(Clone, Debug)]
pub struct Arrow {
pub source: Type,
pub target: Type,
}
impl fmt::Display for Arrow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} → {}", self.source, self.target)
}
}
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct FinalArrow {
pub source: Arc<Final>,
pub target: Arc<Final>,
}
impl fmt::Display for FinalArrow {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} → {}", self.source, self.target)
}
}
impl FinalArrow {
pub fn shallow_clone(&self) -> Self {
FinalArrow {
source: Arc::clone(&self.source),
target: Arc::clone(&self.target),
}
}
}
impl Arrow {
pub fn finalize(&self) -> Result<FinalArrow, Error> {
Ok(FinalArrow {
source: self.source.finalize()?,
target: self.target.finalize()?,
})
}
pub fn for_unit() -> Self {
Arrow {
source: Type::free(new_name("unit_src_")),
target: Type::unit(),
}
}
pub fn for_iden() -> Self {
let new = Type::free(new_name("iden_src_"));
Arrow {
source: new.shallow_clone(),
target: new,
}
}
pub fn for_witness() -> Self {
Arrow {
source: Type::free(new_name("witness_src_")),
target: Type::free(new_name("witness_tgt_")),
}
}
pub fn for_fail() -> Self {
Arrow {
source: Type::free(new_name("fail_src_")),
target: Type::free(new_name("fail_tgt_")),
}
}
pub fn for_jet<J: Jet>(jet: J) -> Self {
Arrow {
source: jet.source_ty().to_type(),
target: jet.target_ty().to_type(),
}
}
pub fn for_const_word(word: &Value) -> Self {
let len = word.len();
assert!(len > 0, "Words must not be the empty bitstring");
assert!(len.is_power_of_two());
let depth = word.len().trailing_zeros();
Arrow {
source: Type::unit(),
target: Type::two_two_n(depth as usize),
}
}
pub fn for_injl(child_arrow: &Arrow) -> Self {
Arrow {
source: child_arrow.source.shallow_clone(),
target: Type::sum(
child_arrow.target.shallow_clone(),
Type::free(new_name("injl_tgt_")),
),
}
}
pub fn for_injr(child_arrow: &Arrow) -> Self {
Arrow {
source: child_arrow.source.shallow_clone(),
target: Type::sum(
Type::free(new_name("injr_tgt_")),
child_arrow.target.shallow_clone(),
),
}
}
pub fn for_take(child_arrow: &Arrow) -> Self {
Arrow {
source: Type::product(
child_arrow.source.shallow_clone(),
Type::free(new_name("take_src_")),
),
target: child_arrow.target.shallow_clone(),
}
}
pub fn for_drop(child_arrow: &Arrow) -> Self {
Arrow {
source: Type::product(
Type::free(new_name("drop_src_")),
child_arrow.source.shallow_clone(),
),
target: child_arrow.target.shallow_clone(),
}
}
pub fn for_pair(lchild_arrow: &Arrow, rchild_arrow: &Arrow) -> Result<Self, Error> {
lchild_arrow.source.unify(
&rchild_arrow.source,
"pair combinator: left source = right source",
)?;
Ok(Arrow {
source: lchild_arrow.source.shallow_clone(),
target: Type::product(
lchild_arrow.target.shallow_clone(),
rchild_arrow.target.shallow_clone(),
),
})
}
pub fn for_comp(lchild_arrow: &Arrow, rchild_arrow: &Arrow) -> Result<Self, Error> {
lchild_arrow.target.unify(
&rchild_arrow.source,
"comp combinator: left target = right source",
)?;
Ok(Arrow {
source: lchild_arrow.source.shallow_clone(),
target: rchild_arrow.target.shallow_clone(),
})
}
pub fn for_case(
lchild_arrow: Option<&Arrow>,
rchild_arrow: Option<&Arrow>,
) -> Result<Self, Error> {
let a = Type::free(new_name("case_a_"));
let b = Type::free(new_name("case_b_"));
let c = Type::free(new_name("case_c_"));
let sum_a_b = Type::sum(a.shallow_clone(), b.shallow_clone());
let prod_sum_a_b_c = Type::product(sum_a_b, c.shallow_clone());
let target = Type::free(String::new());
if let Some(lchild_arrow) = lchild_arrow {
lchild_arrow.source.bind(
Arc::new(Bound::Product(a, c.shallow_clone())),
"case combinator: left source = A × C",
)?;
target.unify(&lchild_arrow.target, "").unwrap();
}
if let Some(rchild_arrow) = rchild_arrow {
rchild_arrow.source.bind(
Arc::new(Bound::Product(b, c)),
"case combinator: left source = B × C",
)?;
target.unify(
&rchild_arrow.target,
"case combinator: left target = right target",
)?;
}
Ok(Arrow {
source: prod_sum_a_b_c,
target,
})
}
pub fn for_disconnect(lchild_arrow: &Arrow, rchild_arrow: &Arrow) -> Result<Self, Error> {
let a = Type::free(new_name("disconnect_a_"));
let b = Type::free(new_name("disconnect_b_"));
let c = rchild_arrow.source.shallow_clone();
let d = rchild_arrow.target.shallow_clone();
let prod_256_a = Bound::Product(Type::two_two_n(8), a.shallow_clone());
let prod_b_c = Bound::Product(b.shallow_clone(), c);
let prod_b_d = Type::product(b, d);
lchild_arrow.source.bind(
Arc::new(prod_256_a),
"disconnect combinator: left source = 2^256 × A",
)?;
lchild_arrow.target.bind(
Arc::new(prod_b_c),
"disconnect combinator: left target = B × C",
)?;
Ok(Arrow {
source: a,
target: prod_b_d,
})
}
pub fn shallow_clone(&self) -> Self {
Arrow {
source: self.source.shallow_clone(),
target: self.target.shallow_clone(),
}
}
}
impl CoreConstructible for Arrow {
fn iden() -> Self {
Self::for_iden()
}
fn unit() -> Self {
Self::for_unit()
}
fn injl(child: &Self) -> Self {
Self::for_injl(child)
}
fn injr(child: &Self) -> Self {
Self::for_injr(child)
}
fn take(child: &Self) -> Self {
Self::for_take(child)
}
fn drop_(child: &Self) -> Self {
Self::for_drop(child)
}
fn comp(left: &Self, right: &Self) -> Result<Self, Error> {
Self::for_comp(left, right)
}
fn case(left: &Self, right: &Self) -> Result<Self, Error> {
Self::for_case(Some(left), Some(right))
}
fn assertl(left: &Self, _: crate::Cmr) -> Result<Self, Error> {
Self::for_case(Some(left), None)
}
fn assertr(_: crate::Cmr, right: &Self) -> Result<Self, Error> {
Self::for_case(None, Some(right))
}
fn pair(left: &Self, right: &Self) -> Result<Self, Error> {
Self::for_pair(left, right)
}
fn fail(_: crate::FailEntropy) -> Self {
Self::for_fail()
}
fn const_word(word: Arc<Value>) -> Self {
Self::for_const_word(&word)
}
}
impl DisconnectConstructible<Arrow> for Arrow {
fn disconnect(left: &Self, right: &Self) -> Result<Self, Error> {
Self::for_disconnect(left, right)
}
}
impl DisconnectConstructible<NoDisconnect> for Arrow {
fn disconnect(left: &Self, _: &NoDisconnect) -> Result<Self, Error> {
Self::for_disconnect(
left,
&Arrow {
source: Type::free("disc_src".into()),
target: Type::free("disc_tgt".into()),
},
)
}
}
impl DisconnectConstructible<Option<&Arrow>> for Arrow {
fn disconnect(left: &Self, right: &Option<&Self>) -> Result<Self, Error> {
match *right {
Some(right) => Self::disconnect(left, right),
None => Self::disconnect(left, &NoDisconnect),
}
}
}
impl<J: Jet> JetConstructible<J> for Arrow {
fn jet(jet: J) -> Self {
Self::for_jet(jet)
}
}
impl<W> WitnessConstructible<W> for Arrow {
fn witness(_: W) -> Self {
Self::for_witness()
}
}