1mod codec;
4pub(crate) mod log;
5mod persist;
6mod stats;
7mod store;
8
9pub(crate) use persist::node_key;
10pub use persist::{
11 Backend, DEFAULT_STORE_BYTES, Persisted, STORE_VERSION, Store, Stored, VERSION_NAME,
12};
13pub(crate) use stats::Recording;
14pub use stats::{CacheStats, Lookup, Outcome};
15pub(crate) use store::joined;
16pub use store::{Cache, CachePolicy, DEFAULT_CACHE_BYTES, DEFAULT_MARK_EVERY, PrunePolicy};
17pub use sva_formula::Hash;
18
19use std::collections::BTreeMap;
20
21use sva_samples::{Buffer, Frames, Label, MachineState};
22
23#[derive(Clone, Debug, PartialEq)]
25pub enum Payload {
26 Segments(Vec<Buffer>),
27 Frames(Box<Frames>),
28 Run(Box<Run>),
29}
30
31#[derive(Clone, Copy, Debug, PartialEq, Eq)]
32pub enum PayloadKind {
33 Segments,
34 Frames,
35 Run,
36}
37
38#[derive(Clone)]
40pub struct Run {
41 pub samples: Buffer,
42 pub marks: BTreeMap<i64, MachineState>,
43 pub parent: Option<Hash>,
44}
45
46impl Run {
47 pub fn end(&self) -> i64 {
48 self.samples.extent().end
49 }
50
51 pub fn bytes(&self) -> usize {
52 let marks: usize = self.marks.values().map(MachineState::bytes).sum();
53 self.samples.len() * self.samples.width * size_of::<f64>() + marks
54 }
55}
56
57impl PartialEq for Run {
59 fn eq(&self, other: &Run) -> bool {
60 self.samples == other.samples
61 }
62}
63
64impl std::fmt::Debug for Run {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("Run")
67 .field("samples", &self.samples.extent())
68 .finish()
69 }
70}
71
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74pub enum Expected {
75 Segments { rate: u32, width: usize },
76 Frames,
77 Run { rate: u32, width: usize },
78}
79
80#[derive(Clone, Debug, PartialEq)]
81pub struct Entry {
82 pub payload: Payload,
83 pub label: Option<Label>,
85}
86
87impl Payload {
88 pub fn run(self) -> Option<Run> {
89 match self {
90 Payload::Run(run) => Some(*run),
91 _ => None,
92 }
93 }
94
95 pub fn bytes(&self) -> usize {
96 match self {
97 Payload::Segments(parts) => parts
98 .iter()
99 .map(|b| b.len() * b.width * size_of::<f64>())
100 .sum(),
101 Payload::Frames(f) => f.width * f.frames * f.bins * 2 * size_of::<f64>(),
102 Payload::Run(run) => run.bytes(),
103 }
104 }
105
106 pub fn answers(&self, expected: Expected) -> bool {
107 match (self, expected) {
108 (Payload::Segments(parts), Expected::Segments { rate, width }) => {
109 parts.iter().all(|b| b.rate == rate && b.width == width)
110 }
111 (Payload::Frames(_), Expected::Frames) => true,
112 (Payload::Run(run), Expected::Run { rate, width }) => {
113 run.samples.rate == rate && run.samples.width == width
114 }
115 _ => false,
116 }
117 }
118}
119
120pub fn frames_key(value: Hash, window: usize, hop: usize) -> Hash {
121 mixed(
122 value,
123 &[window as u64, hop as u64, 0x66_72_61_6d_65_73_00_01],
124 )
125}
126
127pub fn value_key(
129 identity: Hash,
130 step: (i128, i128),
131 rate: u32,
132 width: usize,
133 profile: &sva_samples::Profile,
134) -> Hash {
135 mixed(
136 identity,
137 &[
138 step.0 as u64,
139 step.1 as u64,
140 u64::from(rate),
141 width as u64,
142 profile.precision_bits as u64,
143 profile.ceiling_hz.to_bits(),
144 0x76_61_6c_75_65_00_00_01,
145 ],
146 )
147}
148
149const ADDRESS_ROTATE: u32 = 17;
150
151pub(crate) fn mixed(seed: Hash, parts: &[u64]) -> Hash {
152 let mut lanes = sva_formula::Lanes::<ADDRESS_ROTATE>::from(seed);
153 for part in parts {
154 lanes.word(*part);
155 }
156 lanes.finish()
157}