#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum LocatorPrecision {
Block,
Restart,
Entry,
}
#[derive(Copy, Debug, Clone, PartialEq, Eq)]
pub enum LocatorPolicyEntry {
None,
Enabled {
precision: LocatorPrecision,
block_id_bits: Option<u8>,
slot_bits: Option<u8>,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LocatorPolicy(Vec<LocatorPolicyEntry>);
impl core::ops::Deref for LocatorPolicy {
type Target = [LocatorPolicyEntry];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl LocatorPolicy {
#[must_use]
pub(crate) fn get(&self, level: usize) -> LocatorPolicyEntry {
#[expect(clippy::expect_used, reason = "policy is expected not to be empty")]
self.0
.get(level)
.copied()
.unwrap_or_else(|| self.last().copied().expect("policy should not be empty"))
}
#[must_use]
pub fn disabled() -> Self {
Self::all(LocatorPolicyEntry::None)
}
#[must_use]
pub fn block_level() -> Self {
Self::all(LocatorPolicyEntry::Enabled {
precision: LocatorPrecision::Block,
block_id_bits: None,
slot_bits: None,
})
}
#[must_use]
pub fn all(entry: LocatorPolicyEntry) -> Self {
Self(vec![entry])
}
#[must_use]
pub fn new(policy: impl Into<Vec<LocatorPolicyEntry>>) -> Self {
let policy = policy.into();
assert!(!policy.is_empty(), "locator policy may not be empty");
assert!(policy.len() <= 255, "locator policy is too large");
Self(policy)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn is_enabled(entry: LocatorPolicyEntry) -> bool {
matches!(entry, LocatorPolicyEntry::Enabled { .. })
}
#[test]
fn disabled_policy_reports_no_level_enabled() {
let policy = LocatorPolicy::disabled();
assert!(!is_enabled(policy.get(0)));
assert!(!is_enabled(policy.get(7)));
}
#[test]
fn get_beyond_length_falls_back_to_last_entry() {
let policy = LocatorPolicy::new(vec![
LocatorPolicyEntry::Enabled {
precision: LocatorPrecision::Restart,
block_id_bits: None,
slot_bits: None,
},
LocatorPolicyEntry::None,
]);
assert!(is_enabled(policy.get(0)));
assert!(!is_enabled(policy.get(1)));
assert!(!is_enabled(policy.get(5)));
}
#[test]
fn all_applies_one_entry_to_every_level() {
let policy = LocatorPolicy::all(LocatorPolicyEntry::Enabled {
precision: LocatorPrecision::Entry,
block_id_bits: Some(20),
slot_bits: Some(10),
});
for level in 0..4 {
assert_eq!(
policy.get(level),
LocatorPolicyEntry::Enabled {
precision: LocatorPrecision::Entry,
block_id_bits: Some(20),
slot_bits: Some(10),
},
);
}
}
#[test]
#[should_panic(expected = "locator policy may not be empty")]
fn new_rejects_empty_policy() {
let _ = LocatorPolicy::new(Vec::new());
}
}