use std::time::Duration;
use crate::ir::{expressions::Expr, Guard, LocalFreqRef, StreamReference};
pub trait GuardFormatter {
type Return;
fn stream(&self, sr: StreamReference) -> Self::Return;
fn alive(&self, sr: StreamReference) -> Self::Return;
fn dynamic(&self, expr: Expr) -> Self::Return;
fn global_freq(&self, duration: Duration) -> Self::Return;
fn local_freq(&self, freq_ref: LocalFreqRef) -> Self::Return;
fn and(&self, lhs: Guard, rhs: Guard) -> Self::Return;
fn or(&self, lhs: Guard, rhs: Guard) -> Self::Return;
fn constant(&self, b: bool) -> Self::Return;
fn fast_and(&self, inner: Vec<StreamReference>) -> Self::Return {
self.guard(fast_to_normal_guard(inner, |lhs, rhs| Guard::And {
lhs,
rhs,
}))
}
fn fast_or(&self, inner: Vec<StreamReference>) -> Self::Return {
self.guard(fast_to_normal_guard(inner, |lhs, rhs| Guard::Or {
lhs,
rhs,
}))
}
fn guard(&self, g: Guard) -> Self::Return {
match g {
Guard::Stream(sr) => self.stream(sr),
Guard::Alive(sr) => self.alive(sr),
Guard::Dynamic(expr) => self.dynamic(expr),
Guard::GlobalFreq(duration) => self.global_freq(duration),
Guard::LocalFreq(freq_ref) => self.local_freq(freq_ref),
Guard::And { lhs, rhs } => self.and(*lhs, *rhs),
Guard::Or { lhs, rhs } => self.or(*lhs, *rhs),
Guard::Constant(b) => self.constant(b),
Guard::FastAnd(inner) => self.fast_and(inner),
Guard::FastOr(inner) => self.fast_or(inner),
}
}
}
fn fast_to_normal_guard(
inner: Vec<StreamReference>,
f: impl Fn(Box<Guard>, Box<Guard>) -> Guard,
) -> Guard {
inner
.into_iter()
.map(Guard::Stream)
.reduce(|a, b| f(Box::new(a), Box::new(b)))
.unwrap()
}
pub trait DefaultGuardFormatter
where
Self: GuardFormatter<Return = String>,
{
fn stream(&self, sr: StreamReference) -> String;
fn alive(&self, sr: StreamReference) -> String;
fn dynamic(&self, expr: Expr) -> String;
fn global_freq(&self, duration: Duration) -> String;
fn local_freq(&self, freq_ref: LocalFreqRef) -> String;
fn constant(&self, b: bool) -> String;
fn and(&self, lhs: Guard, rhs: Guard) -> String {
format!("({} && {})", self.guard(lhs), self.guard(rhs))
}
fn or(&self, lhs: Guard, rhs: Guard) -> String {
format!("({} || {})", self.guard(lhs), self.guard(rhs))
}
fn fast_and(&self, inner: Vec<StreamReference>) -> String {
self.guard(fast_to_normal_guard(inner, |lhs, rhs| Guard::And {
lhs,
rhs,
}))
}
fn fast_or(&self, inner: Vec<StreamReference>) -> String {
self.guard(fast_to_normal_guard(inner, |lhs, rhs| Guard::Or {
lhs,
rhs,
}))
}
}
impl<F: DefaultGuardFormatter> GuardFormatter for F {
type Return = String;
fn stream(&self, sr: StreamReference) -> Self::Return {
<Self as DefaultGuardFormatter>::stream(self, sr)
}
fn alive(&self, sr: StreamReference) -> Self::Return {
<Self as DefaultGuardFormatter>::alive(self, sr)
}
fn dynamic(&self, expr: Expr) -> Self::Return {
<Self as DefaultGuardFormatter>::dynamic(self, expr)
}
fn global_freq(&self, duration: Duration) -> Self::Return {
<Self as DefaultGuardFormatter>::global_freq(self, duration)
}
fn local_freq(&self, freq_ref: LocalFreqRef) -> Self::Return {
<Self as DefaultGuardFormatter>::local_freq(self, freq_ref)
}
fn and(&self, lhs: Guard, rhs: Guard) -> Self::Return {
<Self as DefaultGuardFormatter>::and(self, lhs, rhs)
}
fn or(&self, lhs: Guard, rhs: Guard) -> Self::Return {
<Self as DefaultGuardFormatter>::or(self, lhs, rhs)
}
fn constant(&self, b: bool) -> Self::Return {
<Self as DefaultGuardFormatter>::constant(self, b)
}
fn fast_and(&self, inner: Vec<StreamReference>) -> Self::Return {
<Self as DefaultGuardFormatter>::fast_and(self, inner)
}
fn fast_or(&self, inner: Vec<StreamReference>) -> Self::Return {
<Self as DefaultGuardFormatter>::fast_or(self, inner)
}
}