#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CategorySpec {
pub name: String,
pub base_objects: Vec<BaseObject>,
pub structure: StructuralFeatures,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct BaseObject {
pub name: String,
pub description: Option<String>,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StructuralFeatures {
pub terminal: bool,
pub products: bool,
pub initial: bool,
pub coproducts: bool,
pub exponentials: bool,
pub tensor: Option<TensorSpec>,
pub linear_hom: bool,
pub diagonal: DiagonalSpec,
pub terminal_morphism: TerminalSpec,
pub symmetry: bool,
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TensorSpec {
pub symbol: String,
pub unit_symbol: String,
pub associativity: Associativity,
}
impl Default for TensorSpec {
fn default() -> Self {
Self {
symbol: "⊗".to_string(),
unit_symbol: "I".to_string(),
associativity: Associativity::Weak,
}
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Associativity {
Strict,
#[default]
Weak,
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum DiagonalSpec {
#[default]
None,
Universal,
Restricted(Vec<String>),
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TerminalSpec {
#[default]
None,
Universal,
Restricted(Vec<String>),
}
impl CategorySpec {
pub fn is_cartesian(&self) -> bool {
matches!(self.structure.diagonal, DiagonalSpec::Universal)
&& matches!(self.structure.terminal_morphism, TerminalSpec::Universal)
&& self.structure.symmetry
}
pub fn is_linear(&self) -> bool {
matches!(self.structure.diagonal, DiagonalSpec::None)
&& matches!(self.structure.terminal_morphism, TerminalSpec::None)
}
pub fn is_affine(&self) -> bool {
matches!(self.structure.diagonal, DiagonalSpec::None)
&& matches!(self.structure.terminal_morphism, TerminalSpec::Universal)
}
pub fn is_relevant(&self) -> bool {
matches!(self.structure.diagonal, DiagonalSpec::Universal)
&& matches!(self.structure.terminal_morphism, TerminalSpec::None)
}
}