use alloc::{boxed::Box, string::String, vec::Vec};
use core::fmt;
use miden_air::trace::Challenges;
use miden_core::field::ExtensionField;
use crate::Felt;
pub(crate) trait BusMessage<E: ExtensionField<Felt>>: fmt::Display {
fn value(&self, challenges: &Challenges<E>) -> E;
fn source(&self) -> &str;
}
pub(crate) struct BusDebugger<E: ExtensionField<Felt>> {
pub bus_name: String,
pub outstanding_requests: Vec<(E, Box<dyn BusMessage<E>>)>,
pub outstanding_responses: Vec<(E, Box<dyn BusMessage<E>>)>,
}
impl<E> BusDebugger<E>
where
E: ExtensionField<Felt>,
{
pub fn new(bus_name: String) -> Self {
Self {
bus_name,
outstanding_requests: Vec::new(),
outstanding_responses: Vec::new(),
}
}
}
impl<E> BusDebugger<E>
where
E: ExtensionField<Felt>,
{
#[cfg(any(test, feature = "bus-debugger"))]
pub fn add_request(&mut self, request_msg: Box<dyn BusMessage<E>>, challenges: &Challenges<E>) {
let msg_value = request_msg.value(challenges);
if let Some(pos) =
self.outstanding_responses.iter().position(|(value, _)| *value == msg_value)
{
self.outstanding_responses.swap_remove(pos);
} else {
self.outstanding_requests.push((msg_value, request_msg));
}
}
#[cfg(any(test, feature = "bus-debugger"))]
pub fn add_response(
&mut self,
response_msg: Box<dyn BusMessage<E>>,
challenges: &Challenges<E>,
) {
let msg_value = response_msg.value(challenges);
if let Some(pos) =
self.outstanding_requests.iter().position(|(value, _)| *value == msg_value)
{
self.outstanding_requests.swap_remove(pos);
} else {
self.outstanding_responses.push((msg_value, response_msg));
}
}
pub fn is_empty(&self) -> bool {
self.outstanding_requests.is_empty() && self.outstanding_responses.is_empty()
}
}
impl<E> fmt::Display for BusDebugger<E>
where
E: ExtensionField<Felt>,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.is_empty() {
writeln!(f, "Bus '{}' is empty.", self.bus_name)?;
} else {
writeln!(f, "Bus '{}' construction failed.", self.bus_name)?;
if !self.outstanding_requests.is_empty() {
writeln!(f, "The following requests are still outstanding:")?;
for (_value, msg) in &self.outstanding_requests {
writeln!(f, "- {}: {}", msg.source(), msg)?;
}
}
if !self.outstanding_responses.is_empty() {
writeln!(f, "\nThe following responses are still outstanding:")?;
for (_value, msg) in &self.outstanding_responses {
writeln!(f, "- {}: {}", msg.source(), msg)?;
}
}
}
Ok(())
}
}