use std::{cell::RefCell, fmt::Display, hash::Hash, ops::Deref, rc::Rc};
use proc_macro2::{Literal, Span};
use quote::quote;
use syn::{Ident, LitInt, LitStr};
use crate::{Expand, Expanded};
const LOG_BUFFER_SIZE: usize = 1_000;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub enum ClientKind {
MainScope,
Sampler,
Logger,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Client {
pub name: Ident,
pub actor: Ident,
pub reference: bool,
pub label: Option<LitStr>,
pub input_rate: usize,
pub output_rate: usize,
pub kind: ClientKind,
}
impl Client {
pub fn lit_output_rate(&self) -> LitInt {
Literal::usize_unsuffixed(self.output_rate).into()
}
pub fn lit_input_rate(&self) -> LitInt {
Literal::usize_unsuffixed(self.input_rate).into()
}
}
impl Display for Client {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self.kind {
ClientKind::MainScope => write!(
f,
"main client: {} into actor: {} with rates: {} input & {} output",
self.name, self.actor, self.input_rate, self.output_rate
),
ClientKind::Sampler => write!(
f,
"Sampler client: {} into actor: {} with rates: {} input & {} output",
self.name, self.actor, self.input_rate, self.output_rate
),
ClientKind::Logger => write!(
f,
"Arrow client: {} into actor: {} with rates: {} input & {} output",
self.name, self.actor, self.input_rate, self.output_rate
),
}
}
}
impl Expand for Client {
fn expand(&self) -> Expanded {
let Self {
name,
actor,
label,
reference,
kind,
..
} = self.clone();
let (i, o) = (self.lit_input_rate(), self.lit_output_rate());
if reference {
if let Some(label) = label.as_ref() {
quote! {
let #name = #name.into_arcx();
let mut #actor : ::gmt_dos_actors::prelude::Actor<_,#i,#o> =
::gmt_dos_actors::prelude::Actor::new(#name.clone()).name(#label);
}
} else {
quote! {
let #name = #name.into_arcx();
let mut #actor : ::gmt_dos_actors::prelude::Actor<_,#i,#o> =
::gmt_dos_actors::prelude::Actor::new(#name.clone());
}
}
} else {
match kind {
ClientKind::MainScope => {
if let Some(label) = label.as_ref() {
quote! {
let mut #actor : ::gmt_dos_actors::prelude::Actor<_,#i,#o> = (#name,#label).into();
}
} else {
quote! {
let mut #actor : ::gmt_dos_actors::prelude::Actor<_,#i,#o> = #name.into();
}
}
}
ClientKind::Sampler => {
let sampler_type = LitStr::new(
if self.input_rate < self.output_rate {
"downsampling"
} else {
"upsampling"
},
Span::call_site(),
);
quote! {
let mut #actor: ::gmt_dos_actors::prelude::Actor::<_,#i,#o> =
(::gmt_dos_clients::Sampler::default(),format!("{}\n{}:{}",#sampler_type,#i,#o)).into();
}
}
ClientKind::Logger => {
let filename = LitStr::new(actor.to_string().as_str(), Span::call_site());
let buffer_size = LitInt::new(&format!("{LOG_BUFFER_SIZE}"), Span::call_site());
quote! {
let mut #name = ::gmt_dos_clients_arrow::Arrow::builder(#buffer_size).filename(#filename).build().into_arcx();
let mut #actor: ::gmt_dos_actors::prelude::Actor::<_,#i,#o> =
::gmt_dos_actors::prelude::Actor::new(#name.clone()).name(#filename);
}
}
}
}
}
}
#[derive(Debug, Clone, Eq)]
pub struct SharedClient(Rc<RefCell<Client>>);
impl SharedClient {
pub fn new(name: Ident, reference: bool, label: Option<LitStr>) -> Self {
let actor = if reference {
Ident::new(&format!("{name}_actor"), Span::call_site())
} else {
name.clone()
};
Self(Rc::new(RefCell::new(Client {
name,
actor,
label,
reference,
input_rate: 0,
output_rate: 0,
kind: ClientKind::MainScope,
})))
}
pub fn sampler(actor: Ident, name: Ident, output_rate: usize, input_rate: usize) -> Self {
let sampler = Ident::new(
&format!("sampler_{}_{}_{}r{}", actor, name, input_rate, output_rate),
Span::call_site(),
);
Self(Rc::new(RefCell::new(Client {
name: sampler.clone(),
actor: sampler,
label: None,
reference: false,
input_rate,
output_rate,
kind: ClientKind::Sampler,
})))
}
pub fn logger(input_rate: usize) -> Self {
let name = Ident::new(&format!("logging_{}", input_rate), Span::call_site());
let actor = Ident::new(&format!("data_{}", input_rate), Span::call_site());
Self(Rc::new(RefCell::new(Client {
name,
actor,
label: None,
reference: false,
input_rate,
output_rate: 0,
kind: ClientKind::Logger,
})))
}
pub fn actor(&self) -> Ident {
self.0.borrow().actor.clone()
}
}
impl Display for SharedClient {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.borrow().fmt(f)
}
}
impl Expand for SharedClient {
fn expand(&self) -> Expanded {
self.borrow().expand()
}
}
impl Deref for SharedClient {
type Target = RefCell<Client>;
fn deref(&self) -> &Self::Target {
self.0.deref()
}
}
impl Hash for SharedClient {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.borrow().hash(state);
}
}
impl PartialEq for SharedClient {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}