pub mod cipher;
pub mod wcet;
pub use cipher::CipherSuite;
pub use wcet::{calculate_wcet, platforms, PlatformSpecs};
use std::sync::Arc;
use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum LoadingMode {
#[default]
Eager,
MappedDemand,
Streaming,
LazySection,
}
impl LoadingMode {
#[must_use]
pub const fn description(&self) -> &'static str {
match self {
Self::Eager => "Full load into contiguous memory",
Self::MappedDemand => "Memory-mapped with demand paging",
Self::Streaming => "Streaming decompression with ring buffer",
Self::LazySection => "JIT section loading for sparse access",
}
}
#[must_use]
pub const fn supports_zero_copy(&self) -> bool {
matches!(self, Self::MappedDemand)
}
#[must_use]
pub const fn is_deterministic(&self) -> bool {
matches!(self, Self::Eager | Self::Streaming)
}
#[must_use]
pub fn for_memory_budget(budget_bytes: usize, model_size: usize) -> Self {
if budget_bytes >= model_size * 2 {
Self::Eager
} else if budget_bytes >= model_size {
Self::MappedDemand
} else if budget_bytes >= 256 * 1024 {
Self::Streaming
} else {
Self::LazySection
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum VerificationLevel {
UnsafeSkip,
ChecksumOnly,
#[default]
Standard,
Paranoid,
}
impl VerificationLevel {
#[must_use]
pub const fn verifies_checksum(&self) -> bool {
!matches!(self, Self::UnsafeSkip)
}
#[must_use]
pub const fn verifies_signature(&self) -> bool {
matches!(self, Self::Standard | Self::Paranoid)
}
#[must_use]
pub const fn has_runtime_assertions(&self) -> bool {
matches!(self, Self::Paranoid)
}
#[must_use]
pub const fn asil_level(&self) -> &'static str {
match self {
Self::UnsafeSkip => "QM (not safety-relevant)",
Self::ChecksumOnly => "ASIL-A",
Self::Standard => "ASIL-B",
Self::Paranoid => "ASIL-D",
}
}
#[must_use]
pub const fn dal_level(&self) -> &'static str {
match self {
Self::UnsafeSkip => "DAL-E",
Self::ChecksumOnly => "DAL-D",
Self::Standard => "DAL-C",
Self::Paranoid => "DAL-A",
}
}
}
#[derive(Debug)]
pub struct BufferPool {
buffers: Vec<Vec<u8>>,
buffer_size: usize,
free_count: usize,
}
impl BufferPool {
#[must_use]
pub fn new(buffer_count: usize, buffer_size: usize) -> Self {
let buffers = (0..buffer_count).map(|_| vec![0u8; buffer_size]).collect();
Self {
buffers,
buffer_size,
free_count: buffer_count,
}
}
#[must_use]
pub const fn buffer_size(&self) -> usize {
self.buffer_size
}
#[must_use]
pub const fn free_count(&self) -> usize {
self.free_count
}
#[must_use]
pub fn total_count(&self) -> usize {
self.buffers.len()
}
#[must_use]
pub fn total_memory(&self) -> usize {
self.buffers.len() * self.buffer_size
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum Backend {
#[default]
CpuSimd,
Gpu,
Cuda,
Wasm,
Embedded,
}
impl Backend {
#[must_use]
pub const fn supports_simd(&self) -> bool {
matches!(self, Self::CpuSimd)
}
#[must_use]
pub const fn requires_std(&self) -> bool {
!matches!(self, Self::Embedded)
}
#[must_use]
pub const fn is_gpu_accelerated(&self) -> bool {
matches!(self, Self::Gpu | Self::Cuda)
}
#[must_use]
pub const fn requires_nvidia_driver(&self) -> bool {
matches!(self, Self::Cuda)
}
}
#[derive(Debug, Clone)]
pub struct LoadConfig {
pub mode: LoadingMode,
pub max_memory_bytes: Option<usize>,
pub verification: VerificationLevel,
pub backend: Backend,
pub buffer_pool: Option<Arc<BufferPool>>,
pub time_budget: Option<Duration>,
pub streaming: bool,
pub ring_buffer_size: usize,
}
impl Default for LoadConfig {
fn default() -> Self {
Self {
mode: LoadingMode::default(),
max_memory_bytes: None,
verification: VerificationLevel::default(),
backend: Backend::default(),
buffer_pool: None,
time_budget: None,
streaming: false,
ring_buffer_size: 256 * 1024, }
}
}
impl LoadConfig {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub fn embedded(max_memory: usize) -> Self {
Self {
mode: LoadingMode::Eager,
max_memory_bytes: Some(max_memory),
verification: VerificationLevel::Paranoid,
backend: Backend::Embedded,
buffer_pool: None,
time_budget: Some(Duration::from_millis(100)),
streaming: false,
ring_buffer_size: 64 * 1024,
}
}
#[must_use]
pub fn server() -> Self {
Self {
mode: LoadingMode::MappedDemand,
max_memory_bytes: None,
verification: VerificationLevel::Standard,
backend: Backend::CpuSimd,
buffer_pool: None,
time_budget: None,
streaming: false,
ring_buffer_size: 1024 * 1024,
}
}
#[must_use]
pub fn wasm() -> Self {
Self {
mode: LoadingMode::Streaming,
max_memory_bytes: Some(64 * 1024 * 1024), verification: VerificationLevel::Standard,
backend: Backend::Wasm,
buffer_pool: None,
time_budget: None,
streaming: true,
ring_buffer_size: 512 * 1024,
}
}
#[must_use]
pub fn cuda() -> Self {
Self {
mode: LoadingMode::MappedDemand,
max_memory_bytes: None,
verification: VerificationLevel::Standard,
backend: Backend::Cuda,
buffer_pool: None,
time_budget: None,
streaming: false,
ring_buffer_size: 1024 * 1024, }
}
#[must_use]
pub fn gpu() -> Self {
Self {
mode: LoadingMode::MappedDemand,
max_memory_bytes: None,
verification: VerificationLevel::Standard,
backend: Backend::Gpu,
buffer_pool: None,
time_budget: None,
streaming: false,
ring_buffer_size: 1024 * 1024, }
}
#[must_use]
pub fn with_mode(mut self, mode: LoadingMode) -> Self {
self.mode = mode;
self
}
#[must_use]
pub fn with_max_memory(mut self, bytes: usize) -> Self {
self.max_memory_bytes = Some(bytes);
self
}
#[must_use]
pub fn with_verification(mut self, level: VerificationLevel) -> Self {
self.verification = level;
self
}
#[must_use]
pub fn with_backend(mut self, backend: Backend) -> Self {
self.backend = backend;
self
}
#[must_use]
pub fn with_time_budget(mut self, budget: Duration) -> Self {
self.time_budget = Some(budget);
self
}
#[must_use]
pub fn with_streaming(mut self, ring_buffer_size: usize) -> Self {
self.streaming = true;
self.ring_buffer_size = ring_buffer_size;
self
}
#[must_use]
pub fn with_buffer_pool(mut self, pool: Arc<BufferPool>) -> Self {
self.buffer_pool = Some(pool);
self
}
}
#[derive(Debug, Clone)]
pub struct LoadResult {
pub load_time: Duration,
pub memory_used: usize,
pub checksum_verified: bool,
pub signature_verified: bool,
pub pages_loaded: usize,
pub decompression_ratio: f64,
}
impl LoadResult {
#[must_use]
pub fn new(load_time: Duration, memory_used: usize) -> Self {
Self {
load_time,
memory_used,
checksum_verified: false,
signature_verified: false,
pages_loaded: 1,
decompression_ratio: 1.0,
}
}
#[must_use]
pub fn throughput_mbps(&self) -> f64 {
if self.load_time.as_secs_f64() > 0.0 {
(self.memory_used as f64 / (1024.0 * 1024.0)) / self.load_time.as_secs_f64()
} else {
0.0
}
}
}
#[cfg(test)]
#[path = "loading_tests.rs"]
mod tests;