use std::str::FromStr;
use buffa::Enumeration;
use serde::{Deserialize, Serialize};
use crate::UnknownVariant;
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[repr(i32)]
#[non_exhaustive]
pub enum Cardinality {
#[default]
Unspecified = 0,
Low = 1,
Medium = 2,
High = 3,
Unbounded = 4,
}
impl Cardinality {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Unspecified => "unspecified",
Self::Low => "low",
Self::Medium => "medium",
Self::High => "high",
Self::Unbounded => "unbounded",
}
}
#[must_use]
pub const fn cap(self) -> u64 {
match self {
Self::Unspecified => 0,
Self::Low => 10,
Self::Medium => 10_000,
Self::High => 1_000_000,
Self::Unbounded => u64::MAX,
}
}
#[must_use]
pub const fn is_label_compatible(self) -> bool {
matches!(self, Self::Low | Self::Medium)
}
#[must_use]
pub const fn is_measurement_compatible(self) -> bool {
!matches!(self, Self::Unbounded)
}
}
impl Enumeration for Cardinality {
fn from_i32(value: i32) -> Option<Self> {
match value {
0 => Some(Self::Unspecified),
1 => Some(Self::Low),
2 => Some(Self::Medium),
3 => Some(Self::High),
4 => Some(Self::Unbounded),
_ => None,
}
}
fn to_i32(&self) -> i32 {
*self as i32
}
fn proto_name(&self) -> &'static str {
match self {
Self::Unspecified => "CARDINALITY_UNSPECIFIED",
Self::Low => "LOW",
Self::Medium => "MEDIUM",
Self::High => "HIGH",
Self::Unbounded => "UNBOUNDED",
}
}
fn from_proto_name(name: &str) -> Option<Self> {
match name {
"CARDINALITY_UNSPECIFIED" => Some(Self::Unspecified),
"LOW" => Some(Self::Low),
"MEDIUM" => Some(Self::Medium),
"HIGH" => Some(Self::High),
"UNBOUNDED" => Some(Self::Unbounded),
_ => None,
}
}
fn values() -> &'static [Self] {
&[
Self::Unspecified,
Self::Low,
Self::Medium,
Self::High,
Self::Unbounded,
]
}
}
impl FromStr for Cardinality {
type Err = UnknownVariant;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_ascii_lowercase().as_str() {
"low" => Ok(Self::Low),
"medium" => Ok(Self::Medium),
"high" => Ok(Self::High),
"unbounded" => Ok(Self::Unbounded),
_ => Err(UnknownVariant {
kind: "Cardinality",
value: s.to_string(),
}),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_should_round_trip_via_i32() {
for v in Cardinality::values() {
assert_eq!(Cardinality::from_i32(v.to_i32()), Some(*v));
}
}
#[test]
fn test_should_enforce_label_compatibility() {
assert!(Cardinality::Low.is_label_compatible());
assert!(Cardinality::Medium.is_label_compatible());
assert!(!Cardinality::High.is_label_compatible());
assert!(!Cardinality::Unbounded.is_label_compatible());
}
#[test]
fn test_should_compute_caps() {
assert_eq!(Cardinality::Low.cap(), 10);
assert_eq!(Cardinality::Medium.cap(), 10_000);
assert_eq!(Cardinality::High.cap(), 1_000_000);
assert_eq!(Cardinality::Unbounded.cap(), u64::MAX);
}
}