#[allow(unused_imports)]
use alloc::{boxed::Box, format, string::String, string::ToString, vec, vec::Vec};
use core::marker::PhantomData;
use super::arrow::Arrow;
use super::category::Category;
pub struct Op<C>(PhantomData<C>);
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct OpMorphism<M>(pub M);
impl<M: Arrow> Arrow for OpMorphism<M> {
type Object = M::Object;
type Kind = M::Kind;
fn source(&self) -> Self::Object {
self.0.target()
}
fn target(&self) -> Self::Object {
self.0.source()
}
fn kind(&self) -> Self::Kind {
self.0.kind()
}
}
impl<C: Category> Category for Op<C> {
type Object = C::Object;
type Morphism = OpMorphism<C::Morphism>;
fn identity(obj: &Self::Object) -> Self::Morphism {
OpMorphism(C::identity(obj))
}
fn compose(f: &Self::Morphism, g: &Self::Morphism) -> Option<Self::Morphism> {
C::compose(&g.0, &f.0).map(OpMorphism)
}
fn morphisms() -> Vec<Self::Morphism> {
C::morphisms().into_iter().map(OpMorphism).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::category::laws::assert_category_laws;
use crate::category::{Arrow, Concept};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
enum Light {
Red,
Green,
}
impl Concept for Light {
fn variants() -> Vec<Self> {
vec![Light::Red, Light::Green]
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
struct LightEdge {
from: Light,
to: Light,
}
impl Arrow for LightEdge {
type Object = Light;
type Kind = ();
fn source(&self) -> Light {
self.from
}
fn target(&self) -> Light {
self.to
}
fn kind(&self) {}
}
struct LightCat;
impl Category for LightCat {
type Object = Light;
type Morphism = LightEdge;
fn identity(obj: &Light) -> LightEdge {
LightEdge {
from: *obj,
to: *obj,
}
}
fn compose(f: &LightEdge, g: &LightEdge) -> Option<LightEdge> {
if f.to != g.from {
return None;
}
Some(LightEdge {
from: f.from,
to: g.to,
})
}
fn morphisms() -> Vec<LightEdge> {
vec![
LightEdge {
from: Light::Red,
to: Light::Red,
},
LightEdge {
from: Light::Green,
to: Light::Green,
},
LightEdge {
from: Light::Red,
to: Light::Green,
},
LightEdge {
from: Light::Green,
to: Light::Red,
},
]
}
}
#[test]
fn op_preserves_category_laws() {
assert_category_laws::<LightCat>();
assert_category_laws::<Op<LightCat>>();
}
#[test]
fn op_flips_source_and_target() {
let m = LightEdge {
from: Light::Red,
to: Light::Green,
};
let m_op = OpMorphism(m);
assert_eq!(m_op.source(), Light::Green);
assert_eq!(m_op.target(), Light::Red);
}
#[test]
fn op_composition_reverses_order() {
let r_to_g = LightEdge {
from: Light::Red,
to: Light::Green,
};
let g_to_r = LightEdge {
from: Light::Green,
to: Light::Red,
};
let composed = <Op<LightCat>>::compose(&OpMorphism(g_to_r), &OpMorphism(r_to_g)).unwrap();
assert_eq!(composed.source(), Light::Red);
assert_eq!(composed.target(), Light::Red);
}
}