base64-ng 2.0.0

no_std-first Base64 encoding and decoding with strict APIs and a security-heavy release process
Documentation
//! Checked arithmetic helpers for the bounded default provider.

use super::{ProtectionError, ProviderReport, ProviderState, ResourceKind, SlotLifecycle};

pub(super) fn report_from_state<const SLOTS: usize>(
    state: &ProviderState<SLOTS>,
) -> ProviderReport {
    let mut active_and_reserved = 0;
    let mut quarantined = 0;
    let mut permanently_quarantined = 0;
    let mut charged_logical_bytes = 0;
    let mut charged_effective_pages = 0;
    for slot in &state.slots {
        match slot.lifecycle {
            SlotLifecycle::Free => continue,
            SlotLifecycle::Reserved | SlotLifecycle::Active => active_and_reserved += 1,
            SlotLifecycle::Quarantined => quarantined += 1,
            SlotLifecycle::PermanentlyQuarantined => permanently_quarantined += 1,
        }
        charged_logical_bytes += slot.logical_bytes;
        charged_effective_pages += slot.effective_pages;
    }
    ProviderReport {
        health: state.health,
        health_generation: state.health_generation,
        protection_generation: state.protection_generation,
        active_and_reserved,
        quarantined,
        permanently_quarantined,
        tombstoned: 0,
        charged_logical_bytes,
        charged_effective_pages,
    }
}

pub(super) fn check_limit(
    current: usize,
    additional: usize,
    maximum: usize,
    resource: ResourceKind,
) -> Result<(), ProtectionError> {
    if current
        .checked_add(additional)
        .is_none_or(|total| total > maximum)
    {
        Err(ProtectionError::ProtectionResourceExhausted(resource))
    } else {
        Ok(())
    }
}

pub(super) fn effective_pages(
    address: usize,
    len: usize,
    page_size: usize,
) -> Result<usize, ProtectionError> {
    if len == 0 {
        return Ok(0);
    }
    let offset = address % page_size;
    offset
        .checked_add(len)
        .and_then(|span| span.checked_add(page_size - 1))
        .map(|span| span / page_size)
        .ok_or(ProtectionError::LengthOverflow)
}

pub(super) fn next_generation(value: usize) -> usize {
    value.checked_add(1).unwrap_or(0)
}