use super::handle::ShardCommandKind;
const EXPECTED_VARIANTS: [&str; 22] = [
"Get",
"GetRaw",
"Put",
"Delete",
"DeleteIfExpired",
"Commit",
"Range",
"HasLiveInRange",
"Append",
"ReadValue",
"Cas",
"ApplyDurable",
"ApplyDurableTombstone",
"ApplyDurableBatch",
"RecordPromise",
"RecordOwnerEpoch",
"ReserveMinted",
"ReadPromiseState",
"ExportReachable",
"MergeAdopt",
"ScanSequences",
"Shutdown",
];
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum Disposition {
ReadOnly,
PutExpiring,
PutNonExpiring,
Remove,
PhysicalRecheck,
AppendExpiring,
AppendNonExpiring,
RawOverwrite,
DurableExpiring,
DurableNonExpiring,
DurableTombstone,
DurableBatch,
Metadata,
BulkRebuild,
Invalidate,
}
fn classify(kind: &ShardCommandKind) -> Disposition {
match kind {
ShardCommandKind::Get { .. }
| ShardCommandKind::GetRaw { .. }
| ShardCommandKind::Commit { .. }
| ShardCommandKind::Range { .. }
| ShardCommandKind::HasLiveInRange(..)
| ShardCommandKind::ReadValue { .. }
| ShardCommandKind::ReadPromiseState { .. }
| ShardCommandKind::ExportReachable { .. }
| ShardCommandKind::ScanSequences { .. } => Disposition::ReadOnly,
ShardCommandKind::Put { ttl: Some(_), .. } => Disposition::PutExpiring,
ShardCommandKind::Put { ttl: None, .. } => Disposition::PutNonExpiring,
ShardCommandKind::Delete { .. } => Disposition::Remove,
ShardCommandKind::DeleteIfExpired { .. } => Disposition::PhysicalRecheck,
ShardCommandKind::Append { ttl: Some(_), .. } => Disposition::AppendExpiring,
ShardCommandKind::Append { ttl: None, .. } => Disposition::AppendNonExpiring,
ShardCommandKind::Cas { .. } => Disposition::RawOverwrite,
ShardCommandKind::ApplyDurable { ttl: Some(_), .. } => Disposition::DurableExpiring,
ShardCommandKind::ApplyDurable { ttl: None, .. } => Disposition::DurableNonExpiring,
ShardCommandKind::ApplyDurableTombstone { .. } => Disposition::DurableTombstone,
ShardCommandKind::ApplyDurableBatch { items, .. } => {
let _contains_expiring = items.iter().any(|item| item.3.is_some());
let _contains_non_expiring = items.iter().any(|item| item.3.is_none());
Disposition::DurableBatch
}
ShardCommandKind::RecordPromise { .. }
| ShardCommandKind::RecordOwnerEpoch { .. }
| ShardCommandKind::ReserveMinted { .. } => Disposition::Metadata,
ShardCommandKind::MergeAdopt { .. } => Disposition::BulkRebuild,
ShardCommandKind::Shutdown { .. } => Disposition::Invalidate,
}
}
fn declared_variants() -> Vec<&'static str> {
let source = include_str!("handle.rs");
let mut variants = Vec::new();
let mut depth = 0_i32;
let mut in_enum = false;
for line in source.lines() {
if !in_enum {
if line.contains("enum ShardCommandKind {") {
in_enum = true;
depth = 1;
}
continue;
}
let trimmed = line.trim();
if depth == 1
&& let Some(first) = trimmed.as_bytes().first()
&& first.is_ascii_uppercase()
{
let end = trimmed.find(['{', '(', ',']).unwrap_or(trimmed.len());
variants.push(trimmed[..end].trim());
}
depth += i32::try_from(line.matches('{').count()).unwrap_or(i32::MAX);
depth -= i32::try_from(line.matches('}').count()).unwrap_or(i32::MAX);
if depth == 0 {
break;
}
}
variants
}
#[test]
fn shard_command_expiry_disposition_census_is_total() {
let classifier: fn(&ShardCommandKind) -> Disposition = classify;
let _ = classifier;
assert_eq!(declared_variants(), EXPECTED_VARIANTS);
assert_eq!(EXPECTED_VARIANTS.len(), 22);
}