use super::descriptor::AllocationSlotDescriptor;
use super::memory_manager::{
MEMORY_MANAGER_INVALID_ID, MEMORY_MANAGER_MAX_ID, MEMORY_MANAGER_MIN_ID,
MemoryManagerSlotError, validate_memory_manager_id,
};
use serde::{Deserialize, Serialize};
const DIAGNOSTIC_STRING_MAX_BYTES: usize = 256;
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct MemoryManagerIdRange {
pub(crate) start: u8,
pub(crate) end: u8,
}
impl MemoryManagerIdRange {
pub const fn new(start: u8, end: u8) -> Result<Self, MemoryManagerRangeError> {
if start > end {
return Err(MemoryManagerRangeError::InvalidRange { start, end });
}
if start == MEMORY_MANAGER_INVALID_ID {
return Err(MemoryManagerRangeError::InvalidMemoryManagerId { id: start });
}
if end == MEMORY_MANAGER_INVALID_ID {
return Err(MemoryManagerRangeError::InvalidMemoryManagerId { id: end });
}
Ok(Self { start, end })
}
#[must_use]
pub const fn all_usable() -> Self {
Self {
start: MEMORY_MANAGER_MIN_ID,
end: MEMORY_MANAGER_MAX_ID,
}
}
#[must_use]
pub const fn contains(&self, id: u8) -> bool {
id >= self.start && id <= self.end
}
#[must_use]
pub const fn start(&self) -> u8 {
self.start
}
#[must_use]
pub const fn end(&self) -> u8 {
self.end
}
}
#[derive(Clone, Copy, Debug, Eq, thiserror::Error, PartialEq)]
pub enum MemoryManagerRangeError {
#[error("MemoryManager ID range is invalid: start={start} end={end}")]
InvalidRange {
start: u8,
end: u8,
},
#[error("MemoryManager ID {id} is not a usable allocation slot")]
InvalidMemoryManagerId {
id: u8,
},
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub enum MemoryManagerRangeMode {
Reserved,
Allowed,
}
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
pub struct MemoryManagerAuthorityRecord {
pub range: MemoryManagerIdRange,
pub authority: String,
pub mode: MemoryManagerRangeMode,
pub purpose: Option<String>,
}
impl MemoryManagerAuthorityRecord {
pub fn new(
range: MemoryManagerIdRange,
authority: impl Into<String>,
mode: MemoryManagerRangeMode,
purpose: Option<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
let record = Self {
range,
authority: authority.into(),
mode,
purpose,
};
validate_authority_record(&record)?;
Ok(record)
}
}
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)]
pub struct MemoryManagerRangeAuthority {
authorities: Vec<MemoryManagerAuthorityRecord>,
}
impl MemoryManagerRangeAuthority {
#[must_use]
pub const fn new() -> Self {
Self {
authorities: Vec::new(),
}
}
pub fn from_records(
records: Vec<MemoryManagerAuthorityRecord>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
let mut authority = Self::new();
for record in records {
authority = authority.insert_record(record)?;
}
Ok(authority)
}
pub fn reserve(
self,
range: MemoryManagerIdRange,
authority: impl Into<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.reserve_with_purpose(range, authority, None)
}
pub fn reserve_ids(
self,
start: u8,
end: u8,
authority: impl Into<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.reserve(MemoryManagerIdRange::new(start, end)?, authority)
}
pub fn reserve_with_purpose(
self,
range: MemoryManagerIdRange,
authority: impl Into<String>,
purpose: Option<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.insert(range, authority, MemoryManagerRangeMode::Reserved, purpose)
}
pub fn reserve_ids_with_purpose(
self,
start: u8,
end: u8,
authority: impl Into<String>,
purpose: Option<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.reserve_with_purpose(MemoryManagerIdRange::new(start, end)?, authority, purpose)
}
pub fn allow(
self,
range: MemoryManagerIdRange,
authority: impl Into<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.allow_with_purpose(range, authority, None)
}
pub fn allow_ids(
self,
start: u8,
end: u8,
authority: impl Into<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.allow(MemoryManagerIdRange::new(start, end)?, authority)
}
pub fn allow_with_purpose(
self,
range: MemoryManagerIdRange,
authority: impl Into<String>,
purpose: Option<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.insert(range, authority, MemoryManagerRangeMode::Allowed, purpose)
}
pub fn allow_ids_with_purpose(
self,
start: u8,
end: u8,
authority: impl Into<String>,
purpose: Option<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
self.allow_with_purpose(MemoryManagerIdRange::new(start, end)?, authority, purpose)
}
pub fn validate_slot_authority(
&self,
slot: &AllocationSlotDescriptor,
expected_authority: &str,
) -> Result<&MemoryManagerAuthorityRecord, MemoryManagerRangeAuthorityError> {
let id = slot
.memory_manager_id()
.map_err(MemoryManagerRangeAuthorityError::Slot)?;
self.validate_id_authority(id, expected_authority)
}
pub fn validate_slot_authority_mode(
&self,
slot: &AllocationSlotDescriptor,
expected_authority: &str,
expected_mode: MemoryManagerRangeMode,
) -> Result<&MemoryManagerAuthorityRecord, MemoryManagerRangeAuthorityError> {
let id = slot
.memory_manager_id()
.map_err(MemoryManagerRangeAuthorityError::Slot)?;
self.validate_id_authority_mode(id, expected_authority, expected_mode)
}
pub fn validate_id_authority(
&self,
id: u8,
expected_authority: &str,
) -> Result<&MemoryManagerAuthorityRecord, MemoryManagerRangeAuthorityError> {
validate_diagnostic_string("expected_authority", expected_authority)?;
let record = self.covering_record(id)?;
if record.authority != expected_authority {
return Err(MemoryManagerRangeAuthorityError::AuthorityMismatch {
id,
expected_authority: expected_authority.to_string(),
actual_authority: record.authority.clone(),
});
}
Ok(record)
}
pub fn validate_id_authority_mode(
&self,
id: u8,
expected_authority: &str,
expected_mode: MemoryManagerRangeMode,
) -> Result<&MemoryManagerAuthorityRecord, MemoryManagerRangeAuthorityError> {
let record = self.validate_id_authority(id, expected_authority)?;
if record.mode != expected_mode {
return Err(MemoryManagerRangeAuthorityError::ModeMismatch {
id,
authority: record.authority.clone(),
expected_mode,
actual_mode: record.mode,
});
}
Ok(record)
}
pub fn authority_for_id(
&self,
id: u8,
) -> Result<Option<&MemoryManagerAuthorityRecord>, MemoryManagerRangeAuthorityError> {
validate_memory_manager_id(id).map_err(MemoryManagerRangeAuthorityError::Slot)?;
Ok(self
.authorities
.iter()
.find(|record| record.range.contains(id)))
}
#[must_use]
pub fn authorities(&self) -> &[MemoryManagerAuthorityRecord] {
&self.authorities
}
#[must_use]
pub fn to_records(&self) -> Vec<MemoryManagerAuthorityRecord> {
self.authorities.clone()
}
pub fn validate_complete_coverage(
&self,
target: MemoryManagerIdRange,
) -> Result<(), MemoryManagerRangeAuthorityError> {
if self.authorities.is_empty() {
return Err(MemoryManagerRangeAuthorityError::MissingCoverage {
start: target.start(),
end: target.end(),
});
}
for record in &self.authorities {
if record.range.start() < target.start() || record.range.end() > target.end() {
return Err(
MemoryManagerRangeAuthorityError::RangeOutsideCoverageTarget {
start: record.range.start(),
end: record.range.end(),
target_start: target.start(),
target_end: target.end(),
},
);
}
}
let mut next_uncovered = u16::from(target.start());
let target_end = u16::from(target.end());
for record in &self.authorities {
let record_start = u16::from(record.range.start());
let record_end = u16::from(record.range.end());
if record_start > next_uncovered {
return Err(MemoryManagerRangeAuthorityError::MissingCoverage {
start: u8::try_from(next_uncovered).expect("valid MemoryManager ID"),
end: record.range.start() - 1,
});
}
if record_end >= next_uncovered {
next_uncovered = record_end + 1;
}
}
if next_uncovered <= target_end {
return Err(MemoryManagerRangeAuthorityError::MissingCoverage {
start: u8::try_from(next_uncovered).expect("valid MemoryManager ID"),
end: target.end(),
});
}
Ok(())
}
fn insert(
self,
range: MemoryManagerIdRange,
authority: impl Into<String>,
mode: MemoryManagerRangeMode,
purpose: Option<String>,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
let record = MemoryManagerAuthorityRecord {
range,
authority: authority.into(),
mode,
purpose,
};
self.insert_record(record)
}
fn insert_record(
mut self,
record: MemoryManagerAuthorityRecord,
) -> Result<Self, MemoryManagerRangeAuthorityError> {
validate_authority_record(&record)?;
for existing in &self.authorities {
if ranges_overlap(existing.range, record.range) {
return Err(MemoryManagerRangeAuthorityError::OverlappingRanges {
existing_start: existing.range.start(),
existing_end: existing.range.end(),
candidate_start: record.range.start(),
candidate_end: record.range.end(),
});
}
}
self.authorities.push(record);
self.authorities.sort_by_key(|record| record.range.start());
Ok(self)
}
fn covering_record(
&self,
id: u8,
) -> Result<&MemoryManagerAuthorityRecord, MemoryManagerRangeAuthorityError> {
let Some(record) = self.authority_for_id(id)? else {
return Err(MemoryManagerRangeAuthorityError::UnclaimedId { id });
};
Ok(record)
}
}
fn validate_authority_record(
record: &MemoryManagerAuthorityRecord,
) -> Result<(), MemoryManagerRangeAuthorityError> {
validate_diagnostic_string("authority", &record.authority)?;
if let Some(purpose) = &record.purpose {
validate_diagnostic_string("purpose", purpose)?;
}
Ok(())
}
#[derive(Clone, Debug, Eq, thiserror::Error, PartialEq)]
pub enum MemoryManagerRangeAuthorityError {
#[error(transparent)]
Range(#[from] MemoryManagerRangeError),
#[error("{0}")]
Slot(#[from] MemoryManagerSlotError),
#[error(
"MemoryManager authority range {candidate_start}-{candidate_end} overlaps existing range {existing_start}-{existing_end}"
)]
OverlappingRanges {
existing_start: u8,
existing_end: u8,
candidate_start: u8,
candidate_end: u8,
},
#[error("{field} {reason}")]
InvalidDiagnosticString {
field: &'static str,
reason: &'static str,
},
#[error("MemoryManager ID {id} is not covered by an authority range")]
UnclaimedId {
id: u8,
},
#[error(
"MemoryManager ID {id} belongs to authority '{actual_authority}', not '{expected_authority}'"
)]
AuthorityMismatch {
id: u8,
expected_authority: String,
actual_authority: String,
},
#[error(
"MemoryManager ID {id} belongs to authority '{authority}' with mode {actual_mode:?}, not {expected_mode:?}"
)]
ModeMismatch {
id: u8,
authority: String,
expected_mode: MemoryManagerRangeMode,
actual_mode: MemoryManagerRangeMode,
},
#[error("MemoryManager authority coverage is missing range {start}-{end}")]
MissingCoverage {
start: u8,
end: u8,
},
#[error(
"MemoryManager authority range {start}-{end} is outside coverage target {target_start}-{target_end}"
)]
RangeOutsideCoverageTarget {
start: u8,
end: u8,
target_start: u8,
target_end: u8,
},
}
const fn ranges_overlap(left: MemoryManagerIdRange, right: MemoryManagerIdRange) -> bool {
left.start() <= right.end() && right.start() <= left.end()
}
fn validate_diagnostic_string(
field: &'static str,
value: &str,
) -> Result<(), MemoryManagerRangeAuthorityError> {
if value.is_empty() {
return Err(MemoryManagerRangeAuthorityError::InvalidDiagnosticString {
field,
reason: "must not be empty",
});
}
if value.len() > DIAGNOSTIC_STRING_MAX_BYTES {
return Err(MemoryManagerRangeAuthorityError::InvalidDiagnosticString {
field,
reason: "must be at most 256 bytes",
});
}
if !value.is_ascii() {
return Err(MemoryManagerRangeAuthorityError::InvalidDiagnosticString {
field,
reason: "must be ASCII",
});
}
if value.bytes().any(|byte| byte.is_ascii_control()) {
return Err(MemoryManagerRangeAuthorityError::InvalidDiagnosticString {
field,
reason: "must not contain ASCII control characters",
});
}
Ok(())
}
impl crate::policy::RangeAuthority for MemoryManagerRangeAuthority {
type Error = MemoryManagerRangeAuthorityError;
fn validate_slot(&self, slot: &AllocationSlotDescriptor) -> Result<(), Self::Error> {
let id = slot.memory_manager_id()?;
if self.authority_for_id(id)?.is_none() {
return Err(MemoryManagerRangeAuthorityError::UnclaimedId { id });
}
Ok(())
}
}