use std::cell::RefCell;
use std::time::Duration;
use askama::Template;
#[derive(Debug, PartialEq)]
pub(crate) enum ActorDriver {
AtLeastEvery(Duration),
AtMostEvery(Duration),
EventDriven(Vec<Vec<String>>), CapacityDriven(Vec<Vec<String>>), Other(Vec<String>),
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub(crate) enum ConsumePattern {
PeekCopy, TakeCopy, Take, }
#[derive(Eq, PartialEq, Clone, Debug)]
pub(crate) struct Channel {
pub(crate) name: String,
pub(crate) from_mod: String,
pub(crate) to_mod: String,
pub(crate) bundle_struct_mod: String, pub(crate) message_type: String,
pub(crate) peek: bool,
pub(crate) copy: bool,
pub(crate) batch_read: usize,
pub(crate) to_node: String,
pub(crate) from_node: String,
pub(crate) is_unbundled: bool,
pub(crate) batch_write: usize,
pub(crate) capacity: usize,
pub(crate) bundle_index: isize,
pub(crate) rebundle_index: isize,
pub(crate) bundle_on_from: RefCell<bool>,
}
impl Channel {
pub fn needs_tx_single_clone(&self) -> bool {
!self.is_unbundled
}
pub fn needs_rx_single_clone(&self) -> bool {
!self.is_unbundled
}
pub fn has_bundle_index(&self) -> bool {
self.bundle_index>=0
}
pub fn bundle_index(&self) -> isize {
self.bundle_index
}
pub fn tx_prefix_name(&self, channels:&[Channel]) -> String {
if *self.bundle_on_from.borrow() || channels.len()<=1 {
self.from_node.to_lowercase()
} else {
self.tx_prefix_distributed_name()
}
}
pub fn tx_prefix_distributed_name(&self) -> String {
format!("n_to_{}", self.to_node.to_lowercase())
}
pub fn rx_prefix_name(&self, channels:&[Channel]) -> String {
if !*self.bundle_on_from.borrow() || channels.len()<=1 {
self.to_node.to_lowercase()
} else {
self.rx_prefix_distributed_name()
}
}
pub fn rx_prefix_distributed_name(&self) -> String {
format!("{}_to_{}",self.from_node.to_lowercase(), self.to_mod.to_lowercase())
}
pub fn restructured_bundle_rx(&self, _channels:&[Channel]) -> bool {
*self.bundle_on_from.borrow() &&
self.rebundle_index>=0
}
pub fn restructured_bundle(&self) -> bool {
self.rebundle_index>=0 && !self.is_unbundled
}
pub fn rebundle_index(&self) -> isize {
self.rebundle_index
}
pub fn should_build_read_buffer(&self) -> bool {
self.batch_read > 1 && self.copy
}
pub fn should_build_write_buffer(&self) -> bool {
self.batch_write > 1 && self.copy
}
}
#[derive(Default)]
pub(crate) struct Actor {
pub(crate) display_name: String,
pub(crate) display_suffix: Option<usize>,
pub(crate) mod_name: String,
pub(crate) rx_channels: Vec<Vec<Channel>>,
pub(crate) tx_channels: Vec<Vec<Channel>>,
pub(crate) driver: Vec<ActorDriver>,
}
impl Actor {
pub(crate) fn is_on_graph_edge(&self) -> bool {
self.rx_channels.is_empty() || self.tx_channels.is_empty()
}
pub(crate) fn formal_name(&self) -> String {
if let Some(suffix) = self.display_suffix {
format!("{}{}", self.display_name, suffix)
} else {
self.display_name.clone()
}
}
}
#[derive(Template)]
#[template(path = "file_cargo.txt")]
pub(crate) struct CargoTemplate<'a> {
pub(crate) name: &'a str,
}
#[derive(Template)]
#[template(path = "dockerfile.txt")]
pub(crate) struct DockerFileTemplate<'a> {
pub(crate) name: &'a str,
}
#[derive(Template)]
#[template(path = "file_gitignore.txt")]
pub(crate) struct GitIgnoreTemplate {
}
#[derive(Template)]
#[template(path = "file_args.txt")]
pub(crate) struct ArgsTemplate {
}
#[derive(Template)]
#[template(path = "file_main.txt")]
pub(crate) struct MainTemplate<'a> {
pub(crate) note_for_the_user: String,
pub(crate) project_name: String,
pub(crate) actors: &'a Vec<Actor>,
pub(crate) actor_mods: Vec<String>,
pub(crate) channels: &'a Vec<Vec<Channel>>,
}
#[derive(Template)]
#[template(path = "file_actor.txt")]
pub(crate) struct ActorTemplate {
pub(crate) note_for_the_user: String,
pub(crate) display_name: String,
pub(crate) has_bundles: bool,
pub(crate) is_on_graph_edge: bool,
pub(crate) rx_channels: Vec<Vec<Channel>>,
pub(crate) tx_channels: Vec<Vec<Channel>>,
pub(crate) rx_monitor_defs: Vec<String>,
pub(crate) tx_monitor_defs: Vec<String>,
pub(crate) full_driver_block: String,
pub(crate) message_types_to_use: Vec<String>,
pub(crate) message_types_to_define: Vec<String>,
}
#[cfg(test)]
mod additional_tests {
use super::*;
use std::cell::RefCell;
impl Default for Channel {
fn default() -> Self {
Channel {
name: String::new(),
from_mod: String::new(),
to_mod: String::new(),
bundle_struct_mod: String::new(),
message_type: String::new(),
peek: false,
copy: false,
batch_read: 1,
to_node: String::new(),
from_node: String::new(),
is_unbundled: true,
batch_write: 1,
capacity: 0,
bundle_index: -1,
rebundle_index: -1,
bundle_on_from: RefCell::new(true),
}
}
}
#[test]
fn test_channel_needs_tx_single_clone() {
let channel = Channel {
is_unbundled: true,
..Default::default()
};
assert!(!channel.needs_tx_single_clone());
let channel = Channel {
is_unbundled: false,
..Default::default()
};
assert!(channel.needs_tx_single_clone());
}
#[test]
fn test_channel_needs_rx_single_clone() {
let channel = Channel {
is_unbundled: true,
..Default::default()
};
assert!(!channel.needs_rx_single_clone());
let channel = Channel {
is_unbundled: false,
..Default::default()
};
assert!(channel.needs_rx_single_clone());
}
#[test]
fn test_channel_has_bundle_index() {
let channel = Channel {
bundle_index: -1,
..Default::default()
};
assert!(!channel.has_bundle_index());
let channel = Channel {
bundle_index: 0,
..Default::default()
};
assert!(channel.has_bundle_index());
}
#[test]
fn test_channel_bundle_index() {
let channel = Channel {
bundle_index: 5,
..Default::default()
};
assert_eq!(channel.bundle_index(), 5);
}
#[test]
fn test_channel_tx_prefix_name() {
let channel = Channel {
from_node: "FromNode".to_string(),
bundle_on_from: RefCell::new(true),
..Default::default()
};
let channels = vec![channel.clone()];
assert_eq!(channel.tx_prefix_name(&channels), "fromnode");
}
#[test]
fn test_channel_rx_prefix_name() {
let channel = Channel {
to_node: "ToNode".to_string(),
bundle_on_from: RefCell::new(false),
..Default::default()
};
let channels = vec![channel.clone()];
assert_eq!(channel.rx_prefix_name(&channels), "tonode");
}
#[test]
fn test_channel_restructured_bundle_rx() {
let channel = Channel {
rebundle_index: 1,
bundle_on_from: RefCell::new(true),
..Default::default()
};
let channels = vec![channel.clone()];
assert!(channel.restructured_bundle_rx(&channels));
let channel = Channel {
rebundle_index: -1,
bundle_on_from: RefCell::new(true),
..Default::default()
};
let channels = vec![channel.clone()];
assert!(!channel.restructured_bundle_rx(&channels));
}
#[test]
fn test_channel_restructured_bundle() {
let channel = Channel {
rebundle_index: 1,
is_unbundled: false,
..Default::default()
};
assert!(channel.restructured_bundle());
let channel = Channel {
rebundle_index: -1,
is_unbundled: false,
..Default::default()
};
assert!(!channel.restructured_bundle());
let channel = Channel {
rebundle_index: 1,
is_unbundled: true,
..Default::default()
};
assert!(!channel.restructured_bundle());
}
#[test]
fn test_channel_should_build_read_buffer() {
let channel = Channel {
batch_read: 1,
copy: true,
..Default::default()
};
assert!(!channel.should_build_read_buffer());
let channel = Channel {
batch_read: 2,
copy: true,
..Default::default()
};
assert!(channel.should_build_read_buffer());
let channel = Channel {
batch_read: 2,
copy: false,
..Default::default()
};
assert!(!channel.should_build_read_buffer());
}
#[test]
fn test_channel_should_build_write_buffer() {
let channel = Channel {
batch_write: 1,
copy: true,
..Default::default()
};
assert!(!channel.should_build_write_buffer());
let channel = Channel {
batch_write: 2,
copy: true,
..Default::default()
};
assert!(channel.should_build_write_buffer());
let channel = Channel {
batch_write: 2,
copy: false,
..Default::default()
};
assert!(!channel.should_build_write_buffer());
}
#[test]
fn test_actor_is_on_graph_edge() {
let actor = Actor {
rx_channels: vec![],
tx_channels: vec![vec![]],
..Default::default()
};
assert!(actor.is_on_graph_edge());
let actor = Actor {
rx_channels: vec![vec![]],
tx_channels: vec![],
..Default::default()
};
assert!(actor.is_on_graph_edge());
let actor = Actor {
rx_channels: vec![vec![]],
tx_channels: vec![vec![]],
..Default::default()
};
assert!(!actor.is_on_graph_edge());
}
#[test]
fn test_actor_formal_name() {
let actor = Actor {
display_name: "ActorName".to_string(),
display_suffix: Some(1),
..Default::default()
};
assert_eq!(actor.formal_name(), "ActorName1");
let actor = Actor {
display_name: "ActorName".to_string(),
display_suffix: None,
..Default::default()
};
assert_eq!(actor.formal_name(), "ActorName");
}
}