use core::fmt;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Multiplicitas {
Nihil,
Semel,
Omega,
}
impl Multiplicitas {
#[inline]
pub const fn is_nihil(&self) -> bool {
matches!(self, Multiplicitas::Nihil)
}
#[inline]
pub const fn is_semel(&self) -> bool {
matches!(self, Multiplicitas::Semel)
}
#[inline]
pub const fn is_omega(&self) -> bool {
matches!(self, Multiplicitas::Omega)
}
#[inline]
pub const fn allows_zero(&self) -> bool {
matches!(self, Multiplicitas::Nihil | Multiplicitas::Omega)
}
#[inline]
pub const fn requires_use(&self) -> bool {
matches!(self, Multiplicitas::Semel)
}
#[inline]
pub const fn allows_many(&self) -> bool {
matches!(self, Multiplicitas::Omega)
}
#[inline]
pub const fn is_subusage_of(&self, other: &Multiplicitas) -> bool {
match (self, other) {
(Multiplicitas::Nihil, _) => true,
(Multiplicitas::Semel, Multiplicitas::Nihil) => false,
(Multiplicitas::Semel, _) => true,
(Multiplicitas::Omega, Multiplicitas::Omega) => true,
(Multiplicitas::Omega, _) => false,
}
}
#[inline]
pub const fn to_symbol(&self) -> &'static str {
match self {
Multiplicitas::Nihil => "0",
Multiplicitas::Semel => "1",
Multiplicitas::Omega => "ω",
}
}
}
impl Default for Multiplicitas {
#[inline]
fn default() -> Self {
Multiplicitas::Omega
}
}
impl fmt::Display for Multiplicitas {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_symbol())
}
}
pub trait MultiplicitasSemiring {
fn zero() -> Self;
fn one() -> Self;
fn add(self, other: Self) -> Self;
fn mul(self, other: Self) -> Self;
}
impl MultiplicitasSemiring for Multiplicitas {
#[inline]
fn zero() -> Self {
Multiplicitas::Nihil
}
#[inline]
fn one() -> Self {
Multiplicitas::Semel
}
#[inline]
fn add(self, other: Self) -> Self {
match (self, other) {
(Multiplicitas::Omega, _) | (_, Multiplicitas::Omega) => Multiplicitas::Omega,
(Multiplicitas::Semel, _) | (_, Multiplicitas::Semel) => Multiplicitas::Semel,
(Multiplicitas::Nihil, Multiplicitas::Nihil) => Multiplicitas::Nihil,
}
}
#[inline]
fn mul(self, other: Self) -> Self {
match (self, other) {
(Multiplicitas::Nihil, _) | (_, Multiplicitas::Nihil) => Multiplicitas::Nihil,
(Multiplicitas::Semel, x) | (x, Multiplicitas::Semel) => x,
(Multiplicitas::Omega, Multiplicitas::Omega) => Multiplicitas::Omega,
}
}
}
#[inline]
pub fn mult_add(a: Multiplicitas, b: Multiplicitas) -> Multiplicitas {
a.add(b)
}
#[inline]
pub fn mult_mul(a: Multiplicitas, b: Multiplicitas) -> Multiplicitas {
a.mul(b)
}
#[inline]
pub fn is_subusage(a: Multiplicitas, b: Multiplicitas) -> bool {
a.is_subusage_of(&b)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Nihil;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Semel;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct Omega;
pub trait Usage: Copy + Default + 'static {
const VALUE: Multiplicitas;
const ALLOWS_DISCARD: bool;
const ALLOWS_DUP: bool;
}
impl Usage for Nihil {
const VALUE: Multiplicitas = Multiplicitas::Nihil;
const ALLOWS_DISCARD: bool = true;
const ALLOWS_DUP: bool = true; }
impl Usage for Semel {
const VALUE: Multiplicitas = Multiplicitas::Semel;
const ALLOWS_DISCARD: bool = false;
const ALLOWS_DUP: bool = false;
}
impl Usage for Omega {
const VALUE: Multiplicitas = Multiplicitas::Omega;
const ALLOWS_DISCARD: bool = true;
const ALLOWS_DUP: bool = true;
}
impl fmt::Display for Nihil {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "0")
}
}
impl fmt::Display for Semel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "1")
}
}
impl fmt::Display for Omega {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "ω")
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloc::format;
#[test]
fn test_multiplicitas_predicates() {
assert!(Multiplicitas::Nihil.is_nihil());
assert!(!Multiplicitas::Nihil.is_semel());
assert!(!Multiplicitas::Nihil.is_omega());
assert!(!Multiplicitas::Semel.is_nihil());
assert!(Multiplicitas::Semel.is_semel());
assert!(!Multiplicitas::Semel.is_omega());
assert!(!Multiplicitas::Omega.is_nihil());
assert!(!Multiplicitas::Omega.is_semel());
assert!(Multiplicitas::Omega.is_omega());
}
#[test]
fn test_allows_zero() {
assert!(Multiplicitas::Nihil.allows_zero());
assert!(!Multiplicitas::Semel.allows_zero());
assert!(Multiplicitas::Omega.allows_zero());
}
#[test]
fn test_requires_use() {
assert!(!Multiplicitas::Nihil.requires_use());
assert!(Multiplicitas::Semel.requires_use());
assert!(!Multiplicitas::Omega.requires_use());
}
#[test]
fn test_allows_many() {
assert!(!Multiplicitas::Nihil.allows_many());
assert!(!Multiplicitas::Semel.allows_many());
assert!(Multiplicitas::Omega.allows_many());
}
#[test]
fn test_subusage() {
assert!(Multiplicitas::Nihil.is_subusage_of(&Multiplicitas::Nihil));
assert!(Multiplicitas::Nihil.is_subusage_of(&Multiplicitas::Semel));
assert!(Multiplicitas::Nihil.is_subusage_of(&Multiplicitas::Omega));
assert!(!Multiplicitas::Semel.is_subusage_of(&Multiplicitas::Nihil));
assert!(Multiplicitas::Semel.is_subusage_of(&Multiplicitas::Semel));
assert!(Multiplicitas::Semel.is_subusage_of(&Multiplicitas::Omega));
assert!(!Multiplicitas::Omega.is_subusage_of(&Multiplicitas::Nihil));
assert!(!Multiplicitas::Omega.is_subusage_of(&Multiplicitas::Semel));
assert!(Multiplicitas::Omega.is_subusage_of(&Multiplicitas::Omega));
}
#[test]
fn test_semiring_addition() {
assert_eq!(
mult_add(Multiplicitas::Nihil, Multiplicitas::Nihil),
Multiplicitas::Nihil
);
assert_eq!(
mult_add(Multiplicitas::Nihil, Multiplicitas::Semel),
Multiplicitas::Semel
);
assert_eq!(
mult_add(Multiplicitas::Nihil, Multiplicitas::Omega),
Multiplicitas::Omega
);
assert_eq!(
mult_add(Multiplicitas::Semel, Multiplicitas::Semel),
Multiplicitas::Semel
);
assert_eq!(
mult_add(Multiplicitas::Semel, Multiplicitas::Omega),
Multiplicitas::Omega
);
assert_eq!(
mult_add(Multiplicitas::Omega, Multiplicitas::Omega),
Multiplicitas::Omega
);
}
#[test]
fn test_semiring_multiplication() {
assert_eq!(
mult_mul(Multiplicitas::Nihil, Multiplicitas::Nihil),
Multiplicitas::Nihil
);
assert_eq!(
mult_mul(Multiplicitas::Nihil, Multiplicitas::Semel),
Multiplicitas::Nihil
);
assert_eq!(
mult_mul(Multiplicitas::Nihil, Multiplicitas::Omega),
Multiplicitas::Nihil
);
assert_eq!(
mult_mul(Multiplicitas::Semel, Multiplicitas::Nihil),
Multiplicitas::Nihil
);
assert_eq!(
mult_mul(Multiplicitas::Semel, Multiplicitas::Semel),
Multiplicitas::Semel
);
assert_eq!(
mult_mul(Multiplicitas::Semel, Multiplicitas::Omega),
Multiplicitas::Omega
);
assert_eq!(
mult_mul(Multiplicitas::Omega, Multiplicitas::Nihil),
Multiplicitas::Nihil
);
assert_eq!(
mult_mul(Multiplicitas::Omega, Multiplicitas::Semel),
Multiplicitas::Omega
);
assert_eq!(
mult_mul(Multiplicitas::Omega, Multiplicitas::Omega),
Multiplicitas::Omega
);
}
#[test]
fn test_display() {
assert_eq!(format!("{}", Multiplicitas::Nihil), "0");
assert_eq!(format!("{}", Multiplicitas::Semel), "1");
assert_eq!(format!("{}", Multiplicitas::Omega), "ω");
}
#[test]
fn test_type_level_usage() {
assert_eq!(Nihil::VALUE, Multiplicitas::Nihil);
assert_eq!(Semel::VALUE, Multiplicitas::Semel);
assert_eq!(Omega::VALUE, Multiplicitas::Omega);
assert!(Nihil::ALLOWS_DISCARD);
assert!(!Semel::ALLOWS_DISCARD);
assert!(Omega::ALLOWS_DISCARD);
assert!(Nihil::ALLOWS_DUP);
assert!(!Semel::ALLOWS_DUP);
assert!(Omega::ALLOWS_DUP);
}
#[test]
fn test_default() {
assert_eq!(Multiplicitas::default(), Multiplicitas::Omega);
}
}