1use crate::quick_pubkey_check;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5pub enum RawLog<'a> {
6 Invoke(RawInvokeLog<'a>),
7 Success(RawSuccessLog<'a>),
8 Failed(RawFailedLog<'a>),
9 Log(RawProgramLog<'a>),
10 Data(RawDataLog<'a>),
11 Return(RawReturnLog<'a>),
12 Cu(RawCuLog<'a>),
13 Other(RawOtherLog<'a>),
14}
15
16impl<'a> RawLog<'a> {
17 pub fn parse(log: &'a str) -> Self {
18 let trimmed = log.trim();
19
20 if let Some(rest) = trimmed.strip_prefix("Program log: ") {
21 return RawLog::Log(RawProgramLog {
22 raw: log,
23 msg: rest,
24 });
25 }
26
27 if let Some(rest) = trimmed.strip_prefix("Program data: ") {
28 return RawLog::Data(RawDataLog {
29 raw: log,
30 data: rest,
31 });
32 }
33
34 if let Some(rest) = trimmed.strip_prefix("Program return: ") {
35 let Some((program_id, data)) = rest.split_once(' ') else {
36 return RawLog::Other(RawOtherLog { raw: log });
37 };
38
39 return RawLog::Return(RawReturnLog {
40 raw: log,
41 program_id,
42 data,
43 });
44 }
45
46 if let Some(rest) = trimmed.strip_prefix("Program ") {
47 let Some((program_id, suffix)) = rest.split_once(' ') else {
48 return RawLog::Other(RawOtherLog { raw: log });
49 };
50
51 if !quick_pubkey_check(program_id) {
52 return RawLog::Other(RawOtherLog { raw: log });
53 }
54
55 if let Some(depth) = suffix
56 .strip_prefix("invoke [")
57 .and_then(|s| s.strip_suffix(']'))
58 {
59 return depth
60 .parse()
61 .ok()
62 .map(|depth| {
63 RawLog::Invoke(RawInvokeLog {
64 raw: log,
65 program_id,
66 depth,
67 })
68 })
69 .unwrap_or(RawLog::Other(RawOtherLog { raw: log }));
70 }
71
72 if suffix == "success" {
73 return RawLog::Success(RawSuccessLog {
74 raw: log,
75 program_id,
76 });
77 }
78
79 if let Some(err) = suffix.strip_prefix("failed: ") {
80 return RawLog::Failed(RawFailedLog {
81 raw: log,
82 program_id,
83 err,
84 });
85 }
86
87 if let Some((consumed, of_budget)) = suffix
88 .strip_prefix("consumed ")
89 .and_then(|s| s.split_once(" of "))
90 {
91 let Some(budget) = of_budget.strip_suffix(" compute units") else {
92 return RawLog::Other(RawOtherLog { raw: log });
93 };
94
95 return consumed
96 .parse()
97 .ok()
98 .and_then(|consumed| {
99 budget.parse().ok().map(|budget| {
100 RawLog::Cu(RawCuLog {
101 raw: log,
102 program_id,
103 consumed,
104 budget,
105 })
106 })
107 })
108 .unwrap_or(RawLog::Other(RawOtherLog { raw: log }));
109 }
110 }
111
112 RawLog::Other(RawOtherLog { raw: log })
113 }
114}
115
116#[derive(Debug, Clone, PartialEq, Eq)]
120pub struct RawInvokeLog<'a> {
121 pub raw: &'a str,
122 pub program_id: &'a str,
123 pub depth: u8,
124}
125
126#[derive(Debug, Clone, PartialEq, Eq)]
130pub struct RawSuccessLog<'a> {
131 pub raw: &'a str,
132 pub program_id: &'a str,
133}
134
135#[derive(Debug, Clone, PartialEq, Eq)]
139pub struct RawFailedLog<'a> {
140 pub raw: &'a str,
141 pub program_id: &'a str,
142 pub err: &'a str,
143}
144
145#[derive(Debug, Clone, PartialEq, Eq)]
149pub struct RawProgramLog<'a> {
150 pub raw: &'a str,
151 pub msg: &'a str,
152}
153
154#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct RawDataLog<'a> {
159 pub raw: &'a str,
160 pub data: &'a str,
161}
162
163#[derive(Debug, Clone, PartialEq, Eq)]
167pub struct RawReturnLog<'a> {
168 pub raw: &'a str,
169 pub program_id: &'a str,
170 pub data: &'a str,
171}
172
173#[derive(Debug, Clone, PartialEq, Eq)]
177pub struct RawCuLog<'a> {
178 pub raw: &'a str,
179 pub program_id: &'a str,
180 pub consumed: u64,
181 pub budget: u64,
182}
183
184#[derive(Debug, Clone, PartialEq, Eq)]
185pub struct RawOtherLog<'a> {
186 pub raw: &'a str,
187}
188
189mod helper_code {
194 use crate::structured_log::{
195 ComputeUnitsLog, FailedLog, InvokeLog, Log, ReturnLog, SuccessLog,
196 };
197
198 use super::{
199 RawCuLog, RawDataLog, RawFailedLog, RawInvokeLog, RawOtherLog, RawProgramLog, RawReturnLog,
200 RawSuccessLog,
201 };
202
203 impl<'a> Log for RawInvokeLog<'a> {
204 type RawLog = &'a str;
205
206 fn raw_log(&self) -> Self::RawLog {
207 self.raw
208 }
209 }
210
211 impl<'a> Log for RawSuccessLog<'a> {
212 type RawLog = &'a str;
213
214 fn raw_log(&self) -> Self::RawLog {
215 self.raw
216 }
217 }
218
219 impl<'a> Log for RawFailedLog<'a> {
220 type RawLog = &'a str;
221
222 fn raw_log(&self) -> Self::RawLog {
223 self.raw
224 }
225 }
226
227 impl<'a> Log for RawProgramLog<'a> {
228 type RawLog = &'a str;
229
230 fn raw_log(&self) -> Self::RawLog {
231 self.raw
232 }
233 }
234
235 impl<'a> Log for RawDataLog<'a> {
236 type RawLog = &'a str;
237
238 fn raw_log(&self) -> Self::RawLog {
239 self.raw
240 }
241 }
242
243 impl<'a> Log for RawReturnLog<'a> {
244 type RawLog = &'a str;
245
246 fn raw_log(&self) -> Self::RawLog {
247 self.raw
248 }
249 }
250
251 impl<'a> Log for RawCuLog<'a> {
252 type RawLog = &'a str;
253
254 fn raw_log(&self) -> Self::RawLog {
255 self.raw
256 }
257 }
258
259 impl<'a> Log for RawOtherLog<'a> {
260 type RawLog = &'a str;
261
262 fn raw_log(&self) -> Self::RawLog {
263 self.raw
264 }
265 }
266
267 impl<'a> InvokeLog for RawInvokeLog<'a> {
268 type ProgramId = &'a str;
269
270 fn program_id(&self) -> Self::ProgramId {
271 self.program_id
272 }
273
274 fn depth(&self) -> u8 {
275 self.depth
276 }
277 }
278
279 impl<'a> SuccessLog for RawSuccessLog<'a> {
280 type ProgramId = &'a str;
281
282 fn program_id(&self) -> Self::ProgramId {
283 self.program_id
284 }
285 }
286
287 impl<'a> FailedLog for RawFailedLog<'a> {
288 type ProgramId = &'a str;
289 type Err = &'a str;
290
291 fn program_id(&self) -> Self::ProgramId {
292 self.program_id
293 }
294
295 fn err(&self) -> Self::Err {
296 self.err
297 }
298 }
299
300 impl<'a> ReturnLog for RawReturnLog<'a> {
301 type ProgramId = &'a str;
302 type Data = &'a str;
303
304 fn program_id(&self) -> Self::ProgramId {
305 self.program_id
306 }
307
308 fn data(&self) -> Self::Data {
309 self.data
310 }
311 }
312
313 impl<'a> ComputeUnitsLog for RawCuLog<'a> {
314 type ProgramId = &'a str;
315
316 fn program_id(&self) -> Self::ProgramId {
317 self.program_id
318 }
319 }
320}