1use rustev_contract::replay::ReplayBundle;
9
10pub const NOTE_MAX_BYTES: usize = 256;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
15pub enum BundleLoad {
16 Inaccessible,
19 Oversized,
21 Corrupt,
23}
24
25impl BundleLoad {
26 pub fn code(self) -> &'static str {
28 match self {
29 BundleLoad::Inaccessible => "bundle-inaccessible",
30 BundleLoad::Oversized => "bundle-oversized",
31 BundleLoad::Corrupt => "bundle-corrupt",
32 }
33 }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq)]
39pub struct LoadFailure {
40 pub kind: BundleLoad,
41 note: String,
42}
43
44impl LoadFailure {
45 pub fn new(kind: BundleLoad, note: &str) -> LoadFailure {
48 let mut end = note.len().min(NOTE_MAX_BYTES);
49 while !note.is_char_boundary(end) {
50 end -= 1;
51 }
52 LoadFailure {
53 kind,
54 note: note[..end].to_string(),
55 }
56 }
57
58 pub fn note(&self) -> &str {
59 &self.note
60 }
61}
62
63#[derive(Debug, Clone)]
65pub enum BundleInput {
66 Loaded(Box<ReplayBundle>),
67 Failed(LoadFailure),
68}
69
70impl From<ReplayBundle> for BundleInput {
71 fn from(b: ReplayBundle) -> BundleInput {
72 BundleInput::Loaded(Box::new(b))
73 }
74}
75
76impl From<LoadFailure> for BundleInput {
77 fn from(f: LoadFailure) -> BundleInput {
78 BundleInput::Failed(f)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85
86 #[test]
87 fn a_note_is_cut_at_a_character_boundary() {
88 let long = "é".repeat(200);
89 let f = LoadFailure::new(BundleLoad::Corrupt, &long);
90 assert_eq!(f.note().len(), NOTE_MAX_BYTES);
91 let odd = format!("x{long}");
92 let f = LoadFailure::new(BundleLoad::Corrupt, &odd);
93 assert_eq!(f.note().len(), NOTE_MAX_BYTES - 1);
94 assert_eq!(
95 LoadFailure::new(BundleLoad::Oversized, "short").note(),
96 "short"
97 );
98 }
99}