1use sim_kernel::{Expr, Symbol};
2use sim_value::build::entry;
3
4#[derive(Clone, Debug, PartialEq, Eq)]
6pub struct BridgeObligation {
7 pub path: String,
9 pub reason: String,
11 pub expected: String,
13 pub actual: String,
15 pub repair_menu: Vec<String>,
17}
18
19impl BridgeObligation {
20 pub fn new(
22 path: impl Into<String>,
23 reason: impl Into<String>,
24 expected: impl Into<String>,
25 actual: impl Into<String>,
26 repair_menu: Vec<String>,
27 ) -> Self {
28 Self {
29 path: path.into(),
30 reason: reason.into(),
31 expected: expected.into(),
32 actual: actual.into(),
33 repair_menu,
34 }
35 }
36
37 pub fn repair_packet(
39 path: impl Into<String>,
40 reason: impl Into<String>,
41 expected: impl Into<String>,
42 actual: impl Into<String>,
43 ) -> Self {
44 Self::new(
45 path,
46 reason,
47 expected,
48 actual,
49 vec![
50 "repair packet".to_owned(),
51 "fetch missing context".to_owned(),
52 "return receipt".to_owned(),
53 ],
54 )
55 }
56
57 pub fn to_expr(&self) -> Expr {
59 Expr::Map(vec![
60 entry("path", Expr::String(self.path.clone())),
61 entry("reason", Expr::String(self.reason.clone())),
62 entry("expected", Expr::String(self.expected.clone())),
63 entry("actual", Expr::String(self.actual.clone())),
64 entry(
65 "repair-menu",
66 Expr::List(
67 self.repair_menu
68 .iter()
69 .map(|item| Expr::String(item.clone()))
70 .collect(),
71 ),
72 ),
73 ])
74 }
75}
76
77#[derive(Clone, Debug, PartialEq, Eq)]
79pub struct BridgeReport {
80 pub packet_cid: String,
82 pub accepted_parts: Vec<String>,
84 pub rejected_parts: Vec<String>,
86 pub obligations: Vec<BridgeObligation>,
88}
89
90impl BridgeReport {
91 pub fn new(packet_cid: impl Into<String>) -> Self {
93 Self {
94 packet_cid: packet_cid.into(),
95 accepted_parts: Vec::new(),
96 rejected_parts: Vec::new(),
97 obligations: Vec::new(),
98 }
99 }
100
101 pub fn accept(&mut self, id: &Symbol) {
103 let id = id.as_qualified_str();
104 if !self.accepted_parts.contains(&id) {
105 self.accepted_parts.push(id);
106 }
107 }
108
109 pub fn reject(&mut self, id: &Symbol) {
111 let id = id.as_qualified_str();
112 if !self.rejected_parts.contains(&id) {
113 self.rejected_parts.push(id);
114 }
115 }
116
117 pub fn obligate(&mut self, obligation: BridgeObligation) {
119 self.obligations.push(obligation);
120 }
121
122 pub fn accepted(&self) -> bool {
124 self.obligations.is_empty()
125 }
126
127 pub fn to_expr(&self) -> Expr {
129 Expr::Map(vec![
130 entry("bridge-report", Expr::Bool(true)),
131 entry("packet-cid", Expr::String(self.packet_cid.clone())),
132 entry(
133 "accepted-parts",
134 Expr::List(
135 self.accepted_parts
136 .iter()
137 .map(|id| Expr::String(id.clone()))
138 .collect(),
139 ),
140 ),
141 entry(
142 "rejected-parts",
143 Expr::List(
144 self.rejected_parts
145 .iter()
146 .map(|id| Expr::String(id.clone()))
147 .collect(),
148 ),
149 ),
150 entry(
151 "obligations",
152 Expr::List(
153 self.obligations
154 .iter()
155 .map(BridgeObligation::to_expr)
156 .collect(),
157 ),
158 ),
159 ])
160 }
161}