use interface::{Update, Who};
use crate::{
actor::io::{InputObject, OutputObject},
graph::Graph,
trim,
};
use super::Actor;
#[derive(Debug, Hash, Clone)]
pub struct IOData {
pub(crate) name: String,
pub(crate) hash: u64,
pub(crate) n: usize,
pub(crate) rate: usize,
}
impl IOData {
pub fn new(name: String, hash: u64, n: usize, rate: usize) -> Self {
Self {
name,
hash,
n,
rate,
}
}
pub fn hash(&self) -> u64 {
self.hash
}
}
impl PartialEq<u64> for IOData {
fn eq(&self, other: &u64) -> bool {
self.hash == *other
}
}
#[derive(Debug, Hash, Clone)]
pub enum IO {
Bootstrap(IOData),
Regular(IOData),
Unbounded(IOData),
}
impl IO {
pub fn filter<F>(&self, pred: F) -> bool
where
F: Fn(&IOData) -> bool,
{
if self.len() > 1 {
return true;
}
pred(match self {
IO::Bootstrap(data) => data,
IO::Regular(data) => data,
IO::Unbounded(data) => data,
})
}
pub fn filter_by_name(&self, names: &[&str]) -> bool {
if self.len() > 1 {
return true;
}
let io_name = self.name();
!names.iter().any(|name| io_name.contains(name))
}
pub fn len(&self) -> usize {
match self {
IO::Bootstrap(data) => data.n,
IO::Regular(data) => data.n,
IO::Unbounded(data) => data.n,
}
}
pub fn name(&self) -> &str {
match self {
IO::Bootstrap(data) => &data.name,
IO::Regular(data) => &data.name,
IO::Unbounded(data) => &data.name,
}
}
pub fn rate(&self) -> usize {
match self {
IO::Bootstrap(data) => data.rate,
IO::Regular(data) => data.rate,
IO::Unbounded(data) => data.rate,
}
}
}
impl IO {
pub fn hash(&self) -> u64 {
match self {
IO::Bootstrap(data) => data.hash(),
IO::Regular(data) => data.hash(),
IO::Unbounded(data) => data.hash(),
}
}
}
impl PartialEq<u64> for &IO {
fn eq(&self, other: &u64) -> bool {
self.hash() == *other
}
}
impl PartialEq<u64> for IO {
fn eq(&self, other: &u64) -> bool {
self.hash() == *other
}
}
#[derive(Debug, Default, Clone)]
pub struct PlainActorBuilder {
pub(crate) client: String,
pub(crate) inputs: Option<Vec<IO>>,
pub(crate) outputs: Option<Vec<IO>>,
pub(crate) hash: u64,
pub(crate) image: Option<String>,
pub(crate) graph: Option<Graph>,
}
impl PlainActorBuilder {
pub fn inputs(mut self, inputs: Vec<IO>) -> Self {
self.inputs = Some(inputs);
self
}
pub fn outputs(mut self, outputs: Vec<IO>) -> Self {
self.outputs = Some(outputs);
self
}
pub fn graph(mut self, graph: Option<Graph>) -> Self {
self.graph = graph;
self
}
pub fn image(mut self, image: impl ToString) -> Self {
self.image = Some(image.to_string());
self
}
pub fn build(self) -> PlainActor {
PlainActor {
client: self.client,
inputs: self.inputs,
outputs: self.outputs,
graph: self.graph,
hash: self.hash,
image: self.image,
}
}
}
#[derive(Debug, Hash, Default, Clone)]
pub struct PlainActor {
pub(crate) client: String,
pub(crate) inputs: Option<Vec<IO>>,
pub(crate) outputs: Option<Vec<IO>>,
pub(crate) hash: u64,
pub(crate) image: Option<String>,
pub(crate) graph: Option<Graph>,
}
impl PlainActor {
pub fn new(client: impl ToString) -> PlainActorBuilder {
PlainActorBuilder {
client: client.to_string(),
..Default::default()
}
}
pub fn filter_inputs_by_name(mut self, names: &[&str]) -> Option<Vec<IO>> {
self.inputs.take().map(|ios| {
ios.into_iter()
.filter(|io| io.filter_by_name(names))
.collect::<Vec<_>>()
})
}
pub fn filter_outputs_by_name(mut self, names: &[&str]) -> Option<Vec<IO>> {
self.outputs.take().map(|ios| {
ios.into_iter()
.filter(|io| io.filter_by_name(names))
.collect::<Vec<_>>()
})
}
pub fn inputs(&mut self) -> Option<Vec<IO>> {
self.inputs.take()
}
pub fn outputs(&mut self) -> Option<Vec<IO>> {
self.outputs.take()
}
}
impl<C, const NI: usize, const NO: usize> From<&Actor<C, NI, NO>> for PlainActor
where
C: Update,
{
fn from(actor: &Actor<C, NI, NO>) -> Self {
Self {
client: actor.name.as_ref().unwrap_or(&actor.who()).to_owned(),
inputs: actor
.inputs
.as_ref()
.map(|inputs| inputs.iter().map(|o| IO::from((o, NI))).collect()),
outputs: actor
.outputs
.as_ref()
.map(|outputs| outputs.iter().map(|o| IO::from((o, NO))).collect()),
hash: 0,
image: actor.image.as_ref().cloned(),
graph: None,
}
}
}
impl From<(&Box<dyn InputObject>, usize)> for IO {
fn from((value, r): (&Box<dyn InputObject>, usize)) -> Self {
if value.capacity().is_some() {
IO::Regular(IOData::new(value.who(), value.get_hash(), 1, r))
} else {
IO::Unbounded(IOData::new(value.who(), value.get_hash(), 1, r))
}
}
}
impl From<(&Box<dyn OutputObject>, usize)> for IO {
fn from((value, r): (&Box<dyn OutputObject>, usize)) -> Self {
if value.bootstrap() {
IO::Bootstrap(IOData::new(value.who(), value.get_hash(), value.len(), r))
} else {
IO::Regular(IOData::new(value.who(), value.get_hash(), value.len(), r))
}
}
}
impl IO {
pub fn as_formatted_input(&self, actor_hash: u64, color: usize) -> String {
match self {
IO::Bootstrap(input) => format!(
r#"{0} -> {1} [label="{2}", color={3}, style=bold];"#,
input.hash,
actor_hash,
trim(&input.name),
color
),
IO::Regular(input) => format!(
r#"{0} -> {1} [label="{2}", color={3}];"#,
input.hash,
actor_hash,
trim(&input.name),
color
),
IO::Unbounded(input) => format!(
r#"{0} -> {1} [label="{2}", color={3}, style=dashed];"#,
input.hash,
actor_hash,
trim(&input.name),
color
),
}
}
pub fn as_formatted_output(&self, actor_hash: u64, color: usize) -> String {
match self {
IO::Bootstrap(output) => format!(
r"{0} -> {1} [color={2}, style=bold];",
actor_hash, output.hash, color
),
IO::Regular(output) => {
format!("{0} -> {1} [color={2}];", actor_hash, output.hash, color)
}
IO::Unbounded(output) => format!(
r"{0} -> {1} [color={2}, style=dashed];",
actor_hash, output.hash, color
),
}
}
}