use crate::quick_pubkey_check;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RawLog<'a> {
Invoke(RawInvokeLog<'a>),
Success(RawSuccessLog<'a>),
Failed(RawFailedLog<'a>),
Log(RawProgramLog<'a>),
Data(RawDataLog<'a>),
Return(RawReturnLog<'a>),
Cu(RawCuLog<'a>),
Other(RawOtherLog<'a>),
}
impl<'a> RawLog<'a> {
pub fn parse(log: &'a str) -> Self {
let trimmed = log.trim();
if let Some(rest) = trimmed.strip_prefix("Program log: ") {
return RawLog::Log(RawProgramLog {
raw: log,
msg: rest,
});
}
if let Some(rest) = trimmed.strip_prefix("Program data: ") {
return RawLog::Data(RawDataLog {
raw: log,
data: rest,
});
}
if let Some(rest) = trimmed.strip_prefix("Program return: ") {
let Some((program_id, data)) = rest.split_once(' ') else {
return RawLog::Other(RawOtherLog { raw: log });
};
return RawLog::Return(RawReturnLog {
raw: log,
program_id,
data,
});
}
if let Some(rest) = trimmed.strip_prefix("Program ") {
let Some((program_id, suffix)) = rest.split_once(' ') else {
return RawLog::Other(RawOtherLog { raw: log });
};
if !quick_pubkey_check(program_id) {
return RawLog::Other(RawOtherLog { raw: log });
}
if let Some(depth) = suffix
.strip_prefix("invoke [")
.and_then(|s| s.strip_suffix(']'))
{
return depth
.parse()
.ok()
.map(|depth| {
RawLog::Invoke(RawInvokeLog {
raw: log,
program_id,
depth,
})
})
.unwrap_or(RawLog::Other(RawOtherLog { raw: log }));
}
if suffix == "success" {
return RawLog::Success(RawSuccessLog {
raw: log,
program_id,
});
}
if let Some(err) = suffix.strip_prefix("failed: ") {
return RawLog::Failed(RawFailedLog {
raw: log,
program_id,
err,
});
}
if let Some((consumed, of_budget)) = suffix
.strip_prefix("consumed ")
.and_then(|s| s.split_once(" of "))
{
let Some(budget) = of_budget.strip_suffix(" compute units") else {
return RawLog::Other(RawOtherLog { raw: log });
};
return consumed
.parse()
.ok()
.and_then(|consumed| {
budget.parse().ok().map(|budget| {
RawLog::Cu(RawCuLog {
raw: log,
program_id,
consumed,
budget,
})
})
})
.unwrap_or(RawLog::Other(RawOtherLog { raw: log }));
}
}
RawLog::Other(RawOtherLog { raw: log })
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawInvokeLog<'a> {
pub raw: &'a str,
pub program_id: &'a str,
pub depth: u8,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawSuccessLog<'a> {
pub raw: &'a str,
pub program_id: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawFailedLog<'a> {
pub raw: &'a str,
pub program_id: &'a str,
pub err: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawProgramLog<'a> {
pub raw: &'a str,
pub msg: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawDataLog<'a> {
pub raw: &'a str,
pub data: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawReturnLog<'a> {
pub raw: &'a str,
pub program_id: &'a str,
pub data: &'a str,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawCuLog<'a> {
pub raw: &'a str,
pub program_id: &'a str,
pub consumed: u64,
pub budget: u64,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RawOtherLog<'a> {
pub raw: &'a str,
}
mod helper_code {
use crate::structured_log::{
ComputeUnitsLog, FailedLog, InvokeLog, Log, ReturnLog, SuccessLog,
};
use super::{
RawCuLog, RawDataLog, RawFailedLog, RawInvokeLog, RawOtherLog, RawProgramLog, RawReturnLog,
RawSuccessLog,
};
impl<'a> Log for RawInvokeLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawSuccessLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawFailedLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawProgramLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawDataLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawReturnLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawCuLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> Log for RawOtherLog<'a> {
type RawLog = &'a str;
fn raw_log(&self) -> Self::RawLog {
self.raw
}
}
impl<'a> InvokeLog for RawInvokeLog<'a> {
type ProgramId = &'a str;
fn program_id(&self) -> Self::ProgramId {
self.program_id
}
fn depth(&self) -> u8 {
self.depth
}
}
impl<'a> SuccessLog for RawSuccessLog<'a> {
type ProgramId = &'a str;
fn program_id(&self) -> Self::ProgramId {
self.program_id
}
}
impl<'a> FailedLog for RawFailedLog<'a> {
type ProgramId = &'a str;
type Err = &'a str;
fn program_id(&self) -> Self::ProgramId {
self.program_id
}
fn err(&self) -> Self::Err {
self.err
}
}
impl<'a> ReturnLog for RawReturnLog<'a> {
type ProgramId = &'a str;
type Data = &'a str;
fn program_id(&self) -> Self::ProgramId {
self.program_id
}
fn data(&self) -> Self::Data {
self.data
}
}
impl<'a> ComputeUnitsLog for RawCuLog<'a> {
type ProgramId = &'a str;
fn program_id(&self) -> Self::ProgramId {
self.program_id
}
}
}