use core::marker::PhantomData;
pub trait Justifies<Lhs, Rhs> {}
pub struct Rewrite<Lhs, Rhs, Via> {
_phantom: PhantomData<(Lhs, Rhs, Via)>,
}
impl<Lhs, Rhs, Via> Rewrite<Lhs, Rhs, Via> {
pub fn witness() -> Self
where
Via: Justifies<Lhs, Rhs>,
{
Rewrite {
_phantom: PhantomData,
}
}
pub fn sym(self) -> Rewrite<Rhs, Lhs, BySymmetry<Via>> {
Rewrite {
_phantom: PhantomData,
}
}
pub fn then<Rhs2, V2>(
self,
_next: Rewrite<Rhs, Rhs2, V2>,
) -> Rewrite<Lhs, Rhs2, ByTransitivity<Via, V2, Rhs>> {
Rewrite {
_phantom: PhantomData,
}
}
}
pub struct ByAssociativity;
pub struct ByCommutativity;
pub struct ByIdentity;
pub struct ByInverse;
pub struct ByDistribution;
pub struct ByAnnihilation;
pub struct ByTransitivity<V1, V2, Mid = ()>(PhantomData<(V1, V2, Mid)>);
pub struct BySymmetry<V>(PhantomData<V>);
pub struct AssocLeft;
pub struct AssocRight;
pub struct CombineAB;
pub struct CombineBA;
pub struct WithIdentity;
pub struct JustA;
pub struct WithInverse;
pub struct Identity;
pub struct Undistributed;
pub struct Distributed;
pub struct ZeroTimes;
pub struct Zero;
impl Justifies<AssocLeft, AssocRight> for ByAssociativity {}
impl Justifies<AssocRight, AssocLeft> for ByAssociativity {}
impl Justifies<CombineAB, CombineBA> for ByCommutativity {}
impl Justifies<CombineBA, CombineAB> for ByCommutativity {}
impl Justifies<WithIdentity, JustA> for ByIdentity {}
impl Justifies<JustA, WithIdentity> for ByIdentity {}
impl Justifies<WithInverse, Identity> for ByInverse {}
impl Justifies<Identity, WithInverse> for ByInverse {}
impl Justifies<Undistributed, Distributed> for ByDistribution {}
impl Justifies<Distributed, Undistributed> for ByDistribution {}
impl Justifies<ZeroTimes, Zero> for ByAnnihilation {}
impl Justifies<Zero, ZeroTimes> for ByAnnihilation {}
impl<V, Lhs, Rhs> Justifies<Rhs, Lhs> for BySymmetry<V> where V: Justifies<Lhs, Rhs> {}
impl<V1, V2, Lhs, Mid, Rhs> Justifies<Lhs, Rhs> for ByTransitivity<V1, V2, Mid>
where
V1: Justifies<Lhs, Mid>,
V2: Justifies<Mid, Rhs>,
{
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn associativity_rewrite() {
let _: Rewrite<AssocLeft, AssocRight, ByAssociativity> = Rewrite::witness();
let _: Rewrite<AssocRight, AssocLeft, ByAssociativity> = Rewrite::witness();
}
#[test]
fn commutativity_rewrite() {
let _: Rewrite<CombineAB, CombineBA, ByCommutativity> = Rewrite::witness();
}
#[test]
fn identity_rewrite() {
let _: Rewrite<WithIdentity, JustA, ByIdentity> = Rewrite::witness();
let _: Rewrite<JustA, WithIdentity, ByIdentity> = Rewrite::witness();
}
#[test]
fn inverse_rewrite() {
let _: Rewrite<WithInverse, Identity, ByInverse> = Rewrite::witness();
}
#[test]
fn distribution_rewrite() {
let _: Rewrite<Undistributed, Distributed, ByDistribution> = Rewrite::witness();
}
#[test]
fn annihilation_rewrite() {
let _: Rewrite<ZeroTimes, Zero, ByAnnihilation> = Rewrite::witness();
}
#[test]
fn symmetry() {
let step: Rewrite<AssocLeft, AssocRight, ByAssociativity> = Rewrite::witness();
let _back: Rewrite<AssocRight, AssocLeft, BySymmetry<ByAssociativity>> = step.sym();
}
#[test]
fn transitivity_chain() {
let step1: Rewrite<WithIdentity, JustA, ByIdentity> = Rewrite::witness();
let step2: Rewrite<JustA, WithIdentity, ByIdentity> = Rewrite::witness();
let _chained: Rewrite<
WithIdentity,
WithIdentity,
ByTransitivity<ByIdentity, ByIdentity, JustA>,
> = step1.then(step2);
}
#[test]
fn three_step_chain() {
let s1: Rewrite<WithInverse, Identity, ByInverse> = Rewrite::witness();
let s2: Rewrite<Identity, WithInverse, ByInverse> = Rewrite::witness();
let s3: Rewrite<WithInverse, Identity, ByInverse> = Rewrite::witness();
let _: Rewrite<
WithInverse,
Identity,
ByTransitivity<ByTransitivity<ByInverse, ByInverse, Identity>, ByInverse, WithInverse>,
> = s1.then(s2).then(s3);
}
}