owl_structural_model/
cardinality.rs1use crate::StructuralModelError;
4use std::cmp::Ordering;
5
6use serde::{Deserialize, Deserializer, Serialize};
7
8#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize)]
12#[serde(transparent)]
13pub struct Cardinality(String);
14impl Cardinality {
15 pub fn try_new(value: impl Into<String>) -> Result<Self, StructuralModelError> {
19 let value = value.into();
20 if value.is_empty() || !value.bytes().all(|byte| byte.is_ascii_digit()) {
21 return Err(StructuralModelError::InvalidFormat {
22 kind: "cardinality",
23 value,
24 message: "requires nonnegative ASCII decimal digits",
25 });
26 }
27 let digits = value.trim_start_matches('0');
28 Ok(Self(if digits.is_empty() {
29 "0".to_owned()
30 } else {
31 digits.to_owned()
32 }))
33 }
34 #[must_use]
36 pub fn as_str(&self) -> &str {
37 &self.0
38 }
39}
40impl From<u64> for Cardinality {
41 fn from(value: u64) -> Self {
42 Self(value.to_string())
43 }
44}
45
46impl PartialOrd for Cardinality {
47 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
48 Some(self.cmp(other))
49 }
50}
51
52impl Ord for Cardinality {
53 fn cmp(&self, other: &Self) -> Ordering {
54 self.0
55 .len()
56 .cmp(&other.0.len())
57 .then_with(|| self.0.cmp(&other.0))
58 }
59}
60impl<'de> Deserialize<'de> for Cardinality {
61 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
62 Self::try_new(String::deserialize(deserializer)?).map_err(serde::de::Error::custom)
63 }
64}