use std::ops::Deref;
use air_parser::ast::{self, Identifier};
use miden_diagnostics::{SourceSpan, Spanned};
use crate::{
CompileError,
ir::{BackLink, Builder, BusOp, BusOpKind, Link, Op},
};
#[derive(Default, Clone, Eq, Debug, Spanned)]
pub struct Bus {
name: Option<Identifier>,
pub bus_type: ast::BusType,
pub columns: Vec<Link<Op>>,
pub latches: Vec<Link<Op>>,
first: Link<Op>,
last: Link<Op>,
#[span]
span: SourceSpan,
}
impl std::hash::Hash for Bus {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.name.hash(state);
self.bus_type.hash(state);
self.columns.hash(state);
self.latches.hash(state);
}
}
impl PartialEq for Bus {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
&& self.bus_type == other.bus_type
&& self.columns == other.columns
&& self.latches == other.latches
}
}
impl Bus {
pub fn create(name: Identifier, bus_type: ast::BusType, span: SourceSpan) -> Link<Bus> {
Bus {
name: Some(name),
bus_type,
span,
..Default::default()
}
.into()
}
pub fn set_first(&mut self, first: Link<Op>) -> Result<(), CompileError> {
let Op::None(_) = self.first.borrow().deref() else {
return Err(CompileError::Failed);
};
self.first = first;
Ok(())
}
pub fn set_last(&mut self, last: Link<Op>) -> Result<(), CompileError> {
let Op::None(_) = self.last.borrow().deref() else {
return Err(CompileError::Failed);
};
self.last = last;
Ok(())
}
pub fn set_name_unchecked(&mut self, name: Identifier) {
self.name = Some(name);
}
pub fn set_name(&mut self, name: Identifier) {
assert!(
self.name.is_none(),
"Bus name is already set to {}, cannot update to {}",
self.name.unwrap(),
name
);
self.name = Some(name);
}
pub fn get_first(&self) -> Link<Op> {
self.first.clone()
}
pub fn get_last(&self) -> Link<Op> {
self.last.clone()
}
pub fn name(&self) -> Identifier {
self.name.expect("Bus name should have already been set")
}
}
impl Link<Bus> {
pub fn insert(&self, columns: &[Link<Op>], latch: Link<Op>, span: SourceSpan) -> Link<Op> {
self.bus_op(BusOpKind::Insert, columns, latch, span)
}
pub fn remove(&self, columns: &[Link<Op>], latch: Link<Op>, span: SourceSpan) -> Link<Op> {
self.bus_op(BusOpKind::Remove, columns, latch, span)
}
fn bus_op(
&self,
kind: BusOpKind,
columns: &[Link<Op>],
latch: Link<Op>,
span: SourceSpan,
) -> Link<Op> {
let mut bus_op = BusOp::builder().bus(self.clone()).kind(kind).span(span);
for column in columns {
bus_op = bus_op.args(column.clone());
}
let bus_op = bus_op.latch(latch.clone()).build();
self.borrow_mut().columns.push(bus_op.clone());
self.borrow_mut().latches.push(latch.clone());
bus_op
}
pub fn set_name(&self, name: Identifier) {
self.borrow_mut().set_name(name);
}
}
impl BackLink<Bus> {
pub fn get_name(&self) -> Identifier {
self.to_link()
.map(|l| l.borrow().name())
.unwrap_or_else(|| panic!("Bus was dropped"))
}
}