use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Cardinality {
ZeroToOne,
OneToOne,
ZeroToMany,
OneToMany,
}
impl Cardinality {
pub fn is_many(self) -> bool {
matches!(self, Self::ZeroToMany | Self::OneToMany)
}
pub fn is_mandatory(self) -> bool {
matches!(self, Self::OneToOne | Self::OneToMany)
}
pub fn code(self) -> u8 {
match self {
Self::ZeroToOne => 0,
Self::OneToOne => 1,
Self::ZeroToMany => 2,
Self::OneToMany => 3,
}
}
pub fn from_code(code: u8) -> Option<Self> {
Some(match code {
0 => Self::ZeroToOne,
1 => Self::OneToOne,
2 => Self::ZeroToMany,
3 => Self::OneToMany,
_ => return None,
})
}
pub fn notation(self) -> &'static str {
match self {
Self::ZeroToOne => "0..1",
Self::OneToOne => "1..1",
Self::ZeroToMany => "0..N",
Self::OneToMany => "1..N",
}
}
}
impl std::fmt::Display for Cardinality {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(self.notation())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn round_trip_codes() {
for c in [
Cardinality::ZeroToOne,
Cardinality::OneToOne,
Cardinality::ZeroToMany,
Cardinality::OneToMany,
] {
assert_eq!(Cardinality::from_code(c.code()), Some(c));
}
assert_eq!(Cardinality::from_code(99), None);
}
#[test]
fn is_many_and_mandatory() {
assert!(!Cardinality::ZeroToOne.is_many());
assert!(!Cardinality::ZeroToOne.is_mandatory());
assert!(Cardinality::OneToOne.is_mandatory());
assert!(Cardinality::OneToMany.is_many());
assert!(Cardinality::OneToMany.is_mandatory());
assert!(Cardinality::ZeroToMany.is_many());
}
}