use std::{
collections::HashSet,
fmt::Display,
ops::{Deref, DerefMut},
};
use proc_macro2::Span;
use quote::quote;
use syn::{
parse::{Parse, ParseStream},
punctuated::Punctuated,
Ident, Token,
};
use crate::{client::SharedClient, model::Scope, Expand, Expanded, TryExpand};
pub mod clientoutput;
use clientoutput::ClientOutputPair;
use self::clientoutput::Output;
#[derive(Debug, Clone, Default)]
pub struct Chain {
pub clientoutput_pairs: Vec<ClientOutputPair>,
}
impl Display for Chain {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.clientoutput_pairs
.iter()
.map(|clientoutput| clientoutput.to_string())
.collect::<Vec<String>>()
.join(" -> ")
)
}
}
impl From<Vec<ClientOutputPair>> for Chain {
fn from(clientoutput_pairs: Vec<ClientOutputPair>) -> Self {
Self { clientoutput_pairs }
}
}
impl Deref for Chain {
type Target = Vec<ClientOutputPair>;
fn deref(&self) -> &Self::Target {
&self.clientoutput_pairs
}
}
impl DerefMut for Chain {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.clientoutput_pairs
}
}
impl Parse for Chain {
fn parse(input: ParseStream) -> syn::Result<Self> {
Ok(Self {
clientoutput_pairs:
Punctuated::<ClientOutputPair, Token![->]>::parse_separated_nonempty(input)?
.into_iter()
.collect(),
..Default::default()
})
}
}
impl Chain {
pub fn dedup(&mut self, clients: &mut HashSet<SharedClient>) {
self.iter_mut().for_each(|client_output| {
let client = &mut client_output.client;
if !clients.insert(client.clone()) {
*client = clients.get(client).unwrap().clone();
}
});
}
pub fn match_rates(&mut self, flow_rate: usize) {
let mut iter = self.iter_mut().peekable();
loop {
match iter.next() {
Some(ClientOutputPair {
client: output_client,
output: Some(output),
}) => {
if let Some(ClientOutputPair {
client: input_client,
..
}) = iter.peek_mut()
{
let (output_rate, input_rate) = (
&mut output_client.borrow_mut().output_rate,
&mut input_client.borrow_mut().input_rate,
);
if *output_rate == 0 {
*output_rate = flow_rate;
}
if *input_rate == 0 {
*input_rate = flow_rate;
}
if *output_rate != *input_rate {
output.add_rate_transition(*input_rate, *output_rate);
}
} else {
let output_rate = &mut output_client.borrow_mut().output_rate;
if *output_rate == 0 {
*output_rate = flow_rate;
}
}
}
Some(ClientOutputPair {
client: output_client,
output: None,
}) => {
if output_client.borrow_mut().input_rate == 0 {
output_client.borrow_mut().input_rate = flow_rate
};
}
None => break,
}
}
}
pub fn implicits(&self, rate: usize, model_scope: &mut Scope) -> Vec<Chain> {
self.iter()
.filter_map(|client_ouput| match client_ouput {
ClientOutputPair {
client,
output:
Some(Output {
ty,
name,
options: output_options,
scope,
logging,
..
}),
} if *scope == true || *logging == true => {
let mut options = output_options.clone();
options
.get_or_insert(vec![])
.push(Ident::new("unbounded", Span::call_site()));
options.as_mut().map(|options| options.dedup());
let output = Output {
ty: ty.clone(),
name: name.clone(),
options,
rate_transition: None,
scope: false,
logging: false,
};
let left = ClientOutputPair {
client: client.clone(),
output: Some(output),
};
let mut chains = Option::<Vec<Chain>>::None;
if *scope {
chains.get_or_insert(vec![]).push(
vec![
left.clone(),
SharedClient::scope(&ty, &name, rate, model_scope).into(),
]
.into(),
)
}
if *logging {
chains
.get_or_insert(vec![])
.push(vec![left.clone(), SharedClient::logger(rate).into()].into())
}
chains
}
_ => None,
})
.flatten()
.collect()
}
}
impl Expand for Chain {
fn expand(&self) -> Expanded {
let iter = self
.iter()
.skip(1)
.map(|client_output| client_output.client.borrow().into_input());
let outputs: Vec<_> = self
.iter()
.zip(iter)
.filter_map(|(output, into_input)| {
output.try_expand().ok().map(|add_output| {
quote! {
#add_output
#into_input
}
})
})
.collect();
quote!(#(#outputs)*)
}
}