use super::{
BinBuildEnvironment, BinDescription, Calculator, FetchItem,
GetCalibration, Item, Iteration, Result, Scope, SinkBin, SinkNames,
SinkOnlyBin, SinkOnlyBinDescription,
};
use crate::error;
use crossbeam_channel::Sender;
use indexmap::{IndexMap, IndexSet};
static BIN_TYPE: &str = "channelsink";
#[derive(Debug)]
pub struct Bin {
scope: Scope,
sender: Sender<IndexMap<String, Item>>,
sources: IndexMap<String, Box<dyn FetchItem>>,
}
impl SinkBin for Bin {}
impl Calculator for Bin {
fn calculate(&mut self, _iteration: &Iteration) -> Result<()> {
let items = self
.sources
.iter()
.map(|(s, ds)| {
ds.fetch_item(&self.scope).map(|d| (s.to_string(), d))
})
.collect::<Result<IndexMap<String, Item>>>()?;
if self.sender.send(items).is_err() {
error::ChannelSendFailed.fail()?;
}
Ok(())
}
}
impl SinkOnlyBin for Bin {}
#[derive(Debug)]
pub struct Description {
pub sinks: IndexSet<String>,
pub sender: Sender<IndexMap<String, Item>>,
}
impl BinDescription for Description {
type Bin = Bin;
fn check_validity(
&self,
_scope: &Scope,
_get_calibration: &mut dyn GetCalibration,
) -> Result<()> {
Ok(())
}
fn bin_type(&self) -> &'static str {
BIN_TYPE
}
}
impl SinkNames for Description {
fn sink_names(&self) -> IndexSet<String> {
self.sinks.clone()
}
}
impl SinkOnlyBinDescription for Description {
fn build_bin(
&self,
scope: &Scope,
env: &mut dyn BinBuildEnvironment,
) -> Result<Self::Bin> {
Ok(Bin {
scope: scope.clone(),
sender: self.sender.clone(),
sources: self
.sinks
.iter()
.map(|s| env.resolve(s).map(|ds| (s.to_string(), ds)))
.collect::<Result<IndexMap<_, _>>>()?,
})
}
}