vole_document/encode/
court.rs1use crate::accounting::CostBreakdown;
9use crate::container::Descriptor;
10use crate::encode::candidates::{Candidate, CandidateKind};
11use crate::error::{Error, Result};
12use crate::limits::Limits;
13use crate::materialize::materialize;
14
15#[derive(Debug, Clone)]
17pub struct CourtResult {
18 pub kind: CandidateKind,
20 pub bytes: Vec<u8>,
22 pub cost: CostBreakdown,
24 pub candidates_evaluated: u32,
26 pub graph_ops: usize,
28}
29
30pub fn run(input: &[u8], candidates: Vec<Candidate>, limits: Limits) -> Result<CourtResult> {
35 let mut court = Court::new();
36 for c in candidates {
37 court.offer(input, c, limits)?;
38 }
39 court.finish()
40}
41
42pub struct Court {
50 best: Option<(u64, usize, CandidateKind, Vec<u8>, CostBreakdown)>,
51 evaluated: u32,
52}
53
54impl Court {
55 pub fn new() -> Self {
57 Court {
58 best: None,
59 evaluated: 0,
60 }
61 }
62
63 pub fn offer(&mut self, input: &[u8], c: Candidate, limits: Limits) -> Result<()> {
65 self.evaluated += 1;
66 let (bytes, cost) = c.descriptor.serialize()?;
67
68 let parsed = Descriptor::parse(&bytes, limits)?;
70 let out = materialize(&parsed, limits)?;
71 if out != input {
72 return Err(Error::reconstruction_mismatch(format!(
73 "candidate {} did not reproduce the source exactly",
74 c.kind.name()
75 )));
76 }
77
78 let total = cost.total();
79 debug_assert_eq!(total, bytes.len() as u64);
80 let work = c.descriptor.program.ops.len();
81 let key = (total, work, c.kind);
82 let replace = match &self.best {
83 None => true,
84 Some((bt, bw, bk, ..)) => key < (*bt, *bw, *bk),
85 };
86 if replace {
87 self.best = Some((total, work, c.kind, bytes, cost));
88 }
89 Ok(())
90 }
91
92 pub fn finish(self) -> Result<CourtResult> {
94 let (_, work, kind, bytes, cost) = self
95 .best
96 .ok_or_else(|| Error::internal_invariant("no candidates were evaluated"))?;
97 Ok(CourtResult {
98 kind,
99 bytes,
100 cost,
101 candidates_evaluated: self.evaluated,
102 graph_ops: work,
103 })
104 }
105}
106
107impl Default for Court {
108 fn default() -> Self {
109 Court::new()
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116 use crate::encode::candidates;
117
118 #[test]
119 fn raw_candidate_wins_and_is_exact() {
120 let input = b"some bytes that must round trip".to_vec();
121 let cands = candidates::propose(&input, Limits::DEFAULT).unwrap();
122 let expected = cands.len() as u32;
123 let r = run(&input, cands, Limits::DEFAULT).unwrap();
124 assert_eq!(r.kind, CandidateKind::Raw);
125 assert_eq!(r.candidates_evaluated, expected);
129 assert!(r.candidates_evaluated >= 2);
130 assert_eq!(r.cost.total(), r.bytes.len() as u64);
131 let (out, _) = crate::materialize::decode_to_bytes(&r.bytes, Limits::DEFAULT).unwrap();
132 assert_eq!(out, input);
133 }
134
135 #[test]
136 fn empty_input_is_exact() {
137 let input: Vec<u8> = Vec::new();
138 let cands = candidates::propose(&input, Limits::DEFAULT).unwrap();
139 let r = run(&input, cands, Limits::DEFAULT).unwrap();
140 let (out, _) = crate::materialize::decode_to_bytes(&r.bytes, Limits::DEFAULT).unwrap();
141 assert!(out.is_empty());
142 }
143}