use alloc::vec::Vec;
use core::cmp::Reverse;
use vize_l0::{Span, String};
use super::{PassEvent, PassObserver, Remark, RemarkKind, RemarkValue};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RemarkArgValue {
Str(String),
Int(i64),
Bool(bool),
}
impl From<RemarkValue<'_>> for RemarkArgValue {
fn from(value: RemarkValue<'_>) -> Self {
match value {
RemarkValue::Str(text) => Self::Str(String::from(text)),
RemarkValue::Int(number) => Self::Int(number),
RemarkValue::Bool(flag) => Self::Bool(flag),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RecordedArg {
pub key: String,
pub value: RemarkArgValue,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RecordedRemark {
pub stage: String,
pub pass: String,
pub kind: RemarkKind,
pub name: String,
pub span: Span,
pub args: Vec<RecordedArg>,
}
impl RecordedRemark {
#[must_use]
pub fn of(event: &PassEvent<'_>, remark: &Remark<'_>) -> Self {
Self {
stage: String::from(event.pipeline.stage),
pass: String::from(event.desc().name),
kind: remark.kind,
name: String::from(remark.name),
span: remark.span,
args: remark
.args
.iter()
.map(|arg| RecordedArg {
key: String::from(arg.key),
value: RemarkArgValue::from(arg.value),
})
.collect(),
}
}
#[must_use]
pub fn arg_str(&self, key: &str) -> Option<&str> {
self.args.iter().find_map(|arg| match &arg.value {
RemarkArgValue::Str(text) if arg.key.as_str() == key => Some(text.as_str()),
_ => None,
})
}
}
#[derive(Debug, Default)]
pub struct RemarkCollector {
pass_seq: u32,
remarks: Vec<(u32, RecordedRemark)>,
}
impl RemarkCollector {
#[must_use]
pub const fn new() -> Self {
Self {
pass_seq: 0,
remarks: Vec::new(),
}
}
#[must_use]
pub fn len(&self) -> usize {
self.remarks.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.remarks.is_empty()
}
#[must_use]
pub fn finish(mut self) -> Vec<RecordedRemark> {
self.remarks.sort_by(|(a_seq, a), (b_seq, b)| {
(a_seq, a.span.start, Reverse(a.span.end), a.name.as_str()).cmp(&(
b_seq,
b.span.start,
Reverse(b.span.end),
b.name.as_str(),
))
});
self.remarks.into_iter().map(|(_, remark)| remark).collect()
}
}
impl PassObserver for RemarkCollector {
const REMARKS: bool = true;
fn before_pass(&mut self, _event: &PassEvent<'_>) {
self.pass_seq += 1;
}
fn on_remark(&mut self, event: &PassEvent<'_>, remark: &Remark<'_>) {
for (index, arg) in remark.args.iter().enumerate() {
assert!(
remark
.args
.iter()
.take(index)
.all(|seen| seen.key != arg.key),
"remark `{}` from pass `{}` repeats argument `{}`",
remark.name,
event.desc().name,
arg.key
);
}
self.remarks
.push((self.pass_seq, RecordedRemark::of(event, remark)));
}
}