1use sim_kernel::{Expr, Symbol};
2use sim_value::build::entry;
3
4#[derive(Clone, Debug, PartialEq, Eq)]
6pub enum AskFailure {
7 Decode {
9 codec: Symbol,
11 message: String,
13 },
14 Shape {
16 expected: String,
18 diagnostics: Vec<String>,
20 },
21}
22
23impl AskFailure {
24 pub fn to_expr(&self) -> Expr {
26 match self {
27 Self::Decode { codec, message } => Expr::Map(vec![
28 entry(
29 "kind",
30 Expr::Symbol(Symbol::qualified("bridge", "DecodeFailure")),
31 ),
32 entry("codec", Expr::Symbol(codec.clone())),
33 entry("message", Expr::String(message.clone())),
34 ]),
35 Self::Shape {
36 expected,
37 diagnostics,
38 } => Expr::Map(vec![
39 entry(
40 "kind",
41 Expr::Symbol(Symbol::qualified("bridge", "ShapeFailure")),
42 ),
43 entry("expected", Expr::String(expected.clone())),
44 entry(
45 "diagnostics",
46 Expr::Vector(diagnostics.iter().cloned().map(Expr::String).collect()),
47 ),
48 ]),
49 }
50 }
51
52 pub(crate) fn message(&self) -> String {
53 match self {
54 Self::Decode { codec, message } => {
55 format!("decode with {codec} failed: {message}")
56 }
57 Self::Shape {
58 expected,
59 diagnostics,
60 } => {
61 let actual = if diagnostics.is_empty() {
62 "no diagnostics".to_owned()
63 } else {
64 diagnostics.join("; ")
65 };
66 format!("shape {expected} rejected answer: {actual}")
67 }
68 }
69 }
70}
71
72#[derive(Clone, Copy, Debug, PartialEq, Eq)]
74pub struct RepairPolicy {
75 pub max_retries: u8,
77}
78
79impl RepairPolicy {
80 pub fn new(max_retries: u8) -> Self {
82 Self {
83 max_retries: max_retries.min(2),
84 }
85 }
86
87 pub(crate) fn retries(self) -> u8 {
88 self.max_retries.min(2)
89 }
90}
91
92impl Default for RepairPolicy {
93 fn default() -> Self {
94 Self::new(1)
95 }
96}