mod disk;
mod evict;
mod label;
mod memory;
pub use disk::{DiskCache, IO_NANOS_PER_BYTE};
pub use memory::MemoryCache;
pub use sva_formula::Hash;
use std::path::Path;
use std::time::Duration;
use sva_formula::SpectralSum;
use sva_samples::{Buffer, FilterTrace, Frames, Label};
#[derive(Clone, Debug, PartialEq)]
pub enum Payload {
Samples(Box<Buffer>),
Frames(Box<Frames>),
Symbolic(Box<SpectralSum>),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum PayloadKind {
Samples,
Frames,
Symbolic,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Expected {
Samples {
rate: u32,
width: usize,
samples: usize,
},
Frames,
Symbolic,
}
#[derive(Clone, Debug, PartialEq)]
pub struct Entry {
pub payload: Payload,
pub traces: Vec<FilterTrace>,
pub label: Option<Label>,
}
impl Payload {
pub fn kind(&self) -> PayloadKind {
match self {
Payload::Samples(_) => PayloadKind::Samples,
Payload::Frames(_) => PayloadKind::Frames,
Payload::Symbolic(_) => PayloadKind::Symbolic,
}
}
pub fn samples(&self) -> Option<&Buffer> {
match self {
Payload::Samples(buffer) => Some(buffer),
_ => None,
}
}
pub fn symbolic(&self) -> Option<&SpectralSum> {
match self {
Payload::Symbolic(sum) => Some(sum),
_ => None,
}
}
pub fn bytes(&self) -> usize {
match self {
Payload::Samples(b) => b.len() * b.width * size_of::<f64>(),
Payload::Frames(f) => f.width * f.frames * f.bins * 2 * size_of::<f64>(),
Payload::Symbolic(n) => {
size_of::<SpectralSum>()
+ n.lanes
.iter()
.map(|lane| {
lane.atoms.len() * size_of::<sva_formula::SpectralAtom>()
+ (lane.series.len() + lane.modal.len()) * size_of::<SpectralSum>()
})
.sum::<usize>()
}
}
}
pub fn answers(&self, expected: Expected) -> bool {
match (self, expected) {
(
Payload::Samples(b),
Expected::Samples {
rate,
width,
samples,
},
) => b.rate == rate && b.width == width && b.len() == samples,
(Payload::Frames(_), Expected::Frames) => true,
(Payload::Symbolic(_), Expected::Symbolic) => true,
_ => false,
}
}
}
#[derive(Clone, Copy)]
pub struct Cost {
#[cfg(not(target_arch = "wasm32"))]
began: std::time::Instant,
}
impl Cost {
pub fn begun() -> Cost {
Cost {
#[cfg(not(target_arch = "wasm32"))]
began: std::time::Instant::now(),
}
}
pub fn elapsed(self) -> Duration {
#[cfg(not(target_arch = "wasm32"))]
return self.began.elapsed();
#[cfg(target_arch = "wasm32")]
return Duration::ZERO;
}
}
pub fn symbolic_key(src: Hash) -> Hash {
mixed(src, &[0x73_79_6d_62_6f_6c_69_63])
}
pub fn frames_key(buffer: Hash, window: usize, hop: usize) -> Hash {
mixed(
buffer,
&[window as u64, hop as u64, 0x66_72_61_6d_65_73_00_01],
)
}
pub fn buffer_key(
symbolic: Hash,
rate: u32,
origin_secs: f64,
width: usize,
score: sva_samples::AliasScore,
) -> Hash {
mixed(
symbolic,
&[
u64::from(rate),
origin_secs.to_bits(),
width as u64,
u64::from(score == sva_samples::AliasScore::Asked),
0x62_75_66_66_65_72_00_01,
],
)
}
const ADDRESS_ROTATE: u32 = 17;
fn mixed(seed: Hash, parts: &[u64]) -> Hash {
let mut lanes = sva_formula::Lanes::<ADDRESS_ROTATE>::from(seed);
for part in parts {
lanes.word(*part);
}
lanes.finish()
}
pub trait Cache: Sync {
fn load(&self, key: Hash, node: &str, expected: Expected) -> Option<Entry>;
fn store(&self, key: Hash, payload: &Payload, traces: &[FilterTrace], label: Option<&Label>);
fn holds(&self, key: Hash) -> bool;
fn worth_storing(&self, cost: Duration, bytes: usize, kind: PayloadKind) -> bool;
fn sweep(&self);
fn held_bytes(&self) -> u64;
fn evicted_bytes(&self) -> u64;
fn faults(&self) -> u64 {
0
}
fn max_bytes(&self) -> u64;
fn dir(&self) -> Option<&Path> {
None
}
}