use std::marker::PhantomData;
use super::FormulaSubscriber;
use crate::{
Error, Sample, logical_meter::logical_meter_actor, metric::Metric, quantity::Quantity,
};
use async_trait::async_trait;
use tokio::sync::{broadcast, mpsc, oneshot};
pub enum Aggregation {}
pub enum Coalesce {}
pub struct GraphFormula<M: Metric, K> {
formula: frequenz_microgrid_component_graph::Formula,
instructions_tx: mpsc::Sender<logical_meter_actor::Instruction>,
phantom: PhantomData<(M, K)>,
}
pub type AggregationFormula<M> = GraphFormula<M, Aggregation>;
pub type CoalesceFormula<M> = GraphFormula<M, Coalesce>;
impl<M: Metric, K> Clone for GraphFormula<M, K> {
fn clone(&self) -> Self {
Self {
formula: self.formula.clone(),
instructions_tx: self.instructions_tx.clone(),
phantom: PhantomData,
}
}
}
impl<M: Metric, K> std::fmt::Display for GraphFormula<M, K> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}::({})", M::METRIC.as_str_name(), self.formula)
}
}
#[async_trait]
impl<Q: Quantity + 'static, M: Metric<QuantityType = Q> + Sync + Send, K: Sync + Send>
FormulaSubscriber for GraphFormula<M, K>
{
type QuantityType = Q;
async fn subscribe(&self) -> Result<broadcast::Receiver<Sample<Q>>, Error> {
let (tx, rx) = oneshot::channel();
self.instructions_tx
.send(logical_meter_actor::Instruction::SubscribeFormula {
formula: self.formula.to_string(),
metric: M::METRIC,
response_tx: tx.try_into()?,
})
.await
.map_err(|e| Error::connection_failure(format!("Could not send instruction: {e}")))?;
let receiver = rx.await.map_err(|e| {
Error::connection_failure(format!("Could not receive instruction: {e}"))
})?;
Ok(receiver)
}
}
impl<M: Metric, K> GraphFormula<M, K> {
pub(super) fn new(
formula: frequenz_microgrid_component_graph::Formula,
instructions_tx: mpsc::Sender<logical_meter_actor::Instruction>,
) -> Self {
Self {
formula,
instructions_tx,
phantom: PhantomData,
}
}
}