use std::error::Error;
use std::fmt::{self, Display, Formatter};
use serde::{Deserialize, Serialize};
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum WorkloadClassV1 {
InteractiveSearch,
BatchAnalytics,
StreamingIngest,
BulkBackfill,
InternalMaintenance,
}
impl WorkloadClassV1 {
pub const ALL: [Self; 5] = [
Self::InteractiveSearch,
Self::BatchAnalytics,
Self::StreamingIngest,
Self::BulkBackfill,
Self::InternalMaintenance,
];
pub const PUBLIC: [Self; 4] = [
Self::InteractiveSearch,
Self::BatchAnalytics,
Self::StreamingIngest,
Self::BulkBackfill,
];
#[must_use]
pub const fn is_public(self) -> bool {
!matches!(self, Self::InternalMaintenance)
}
const fn bit(self) -> u8 {
match self {
Self::InteractiveSearch => 1 << 0,
Self::BatchAnalytics => 1 << 1,
Self::StreamingIngest => 1 << 2,
Self::BulkBackfill => 1 << 3,
Self::InternalMaintenance => 1 << 4,
}
}
}
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct WorkloadClassCapabilitiesV1(u8);
impl WorkloadClassCapabilitiesV1 {
#[must_use]
pub const fn empty() -> Self {
Self(0)
}
pub fn from_public_classes(
classes: impl IntoIterator<Item = WorkloadClassV1>,
) -> Result<Self, WorkloadClassCapabilityError> {
let mut value = Self::empty();
for class in classes {
if !class.is_public() {
return Err(WorkloadClassCapabilityError::InternalClassAtPublicBoundary);
}
value.0 |= class.bit();
}
if value.is_empty() {
return Err(WorkloadClassCapabilityError::Empty);
}
Ok(value)
}
#[must_use]
pub const fn allows(self, class: WorkloadClassV1) -> bool {
self.0 & class.bit() != 0
}
#[must_use]
pub const fn is_empty(self) -> bool {
self.0 == 0
}
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum WorkloadClassCapabilityError {
Empty,
InternalClassAtPublicBoundary,
}
impl Display for WorkloadClassCapabilityError {
fn fmt(&self, formatter: &mut Formatter<'_>) -> fmt::Result {
match self {
Self::Empty => formatter.write_str("workload-class capability set is empty"),
Self::InternalClassAtPublicBoundary => {
formatter.write_str("internal-maintenance class is not a public capability")
}
}
}
}
impl Error for WorkloadClassCapabilityError {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn public_capabilities_are_exact_and_internal_is_refused() -> Result<(), Box<dyn Error>> {
let capabilities = WorkloadClassCapabilitiesV1::from_public_classes([
WorkloadClassV1::InteractiveSearch,
WorkloadClassV1::BulkBackfill,
])?;
assert!(capabilities.allows(WorkloadClassV1::InteractiveSearch));
assert!(capabilities.allows(WorkloadClassV1::BulkBackfill));
assert!(!capabilities.allows(WorkloadClassV1::BatchAnalytics));
assert!(!capabilities.allows(WorkloadClassV1::InternalMaintenance));
assert_eq!(
WorkloadClassCapabilitiesV1::from_public_classes([WorkloadClassV1::InternalMaintenance]),
Err(WorkloadClassCapabilityError::InternalClassAtPublicBoundary)
);
Ok(())
}
}