use super::{DisciplineRow, FaultRow, LinkRow, NetworkDeclaration, ScheduleRow};
use crate::bounded::Overflow;
use crate::descriptor::DirectBinding;
use crate::descriptor::emitting::{
derive_attribute, direct_path, doc_attribute, fallible_return, from_impl, owned_direct_path,
};
use crate::descriptor::fault::NETWORK_FAULT_ARMS;
use crate::token::{GeneratedDelimiter, GeneratedToken, absolute_path, vector};
pub(super) const RESERVED: [&str; 2] = [TOPOLOGY_ROAD, FAULT_ENUM];
const TOPOLOGY_ROAD: &str = "topology";
const FAULT_ENUM: &str = "Fault";
pub fn rendered(declaration: &NetworkDeclaration) -> Result<Vec<GeneratedToken>, Overflow> {
let mut tokens = Vec::new();
doc_attribute(
"The generated network builders: the declared topology, and one function per declared schedule.",
&mut tokens,
)?;
tokens.push(GeneratedToken::word("pub"));
tokens.push(GeneratedToken::word("mod"));
tokens.push(GeneratedToken::word(declaration.module()));
let mut body = Vec::new();
fault_enum(declaration.harness(), &mut body)?;
topology_fn(declaration, &mut body)?;
for schedule in declaration.schedules() {
schedule_fn(declaration, schedule, &mut body)?;
}
tokens.push(GeneratedToken::group(GeneratedDelimiter::Brace, body)?);
Ok(tokens)
}
fn fault_enum(harness: &DirectBinding, into: &mut Vec<GeneratedToken>) -> Result<(), Overflow> {
doc_attribute(
"Everything a generated builder can refuse, carried as itself.",
into,
)?;
derive_attribute(&["Debug", "Clone", "PartialEq", "Eq"], into)?;
into.push(GeneratedToken::word("pub"));
into.push(GeneratedToken::word("enum"));
into.push(GeneratedToken::word(FAULT_ENUM));
let mut arms = Vec::new();
for (arm, path, documentation) in &NETWORK_FAULT_ARMS {
doc_attribute(documentation, &mut arms)?;
arms.push(GeneratedToken::word(arm));
let mut carried = Vec::new();
direct_path(harness, path, &mut carried);
arms.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
carried,
)?);
arms.push(GeneratedToken::alone(','));
}
into.push(GeneratedToken::group(GeneratedDelimiter::Brace, arms)?);
for (arm, path, _documentation) in &NETWORK_FAULT_ARMS {
from_impl(owned_direct_path(harness, path), FAULT_ENUM, arm, into)?;
}
Ok(())
}
fn node_expr(
harness: &DirectBinding,
namespace: &str,
node: &str,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
direct_path(harness, &["network", "NodeRef", "declared"], into);
let mut inner = Vec::new();
direct_path(
harness,
&["descriptor", "NamespacedName", "named"],
&mut inner,
);
inner.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
vec![
GeneratedToken::text(namespace),
GeneratedToken::alone(','),
GeneratedToken::text(node),
],
)?);
inner.push(GeneratedToken::alone('?'));
into.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
inner,
)?);
Ok(())
}
fn link_expr(
harness: &DirectBinding,
namespace: &str,
link: &LinkRow,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
direct_path(harness, &["network", "Link", "between"], into);
let mut inner = Vec::new();
node_expr(harness, namespace, link.from(), &mut inner)?;
inner.push(GeneratedToken::alone(','));
node_expr(harness, namespace, link.to(), &mut inner)?;
into.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
inner,
)?);
Ok(())
}
fn topology_fn(
declaration: &NetworkDeclaration,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
doc_attribute("The declared topology.", into)?;
into.push(GeneratedToken::word("pub"));
into.push(GeneratedToken::word("fn"));
into.push(GeneratedToken::word(TOPOLOGY_ROAD));
into.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
Vec::new(),
)?);
let mut ok_seat = Vec::new();
direct_path(
declaration.harness(),
&["network", "Topology"],
&mut ok_seat,
);
fallible_return(ok_seat, FAULT_ENUM, into);
let mut body = Vec::new();
body.extend(absolute_path(&["core", "result", "Result", "Ok"]));
let mut inner = Vec::new();
direct_path(
declaration.harness(),
&["network", "Topology", "declared"],
&mut inner,
);
let mut nodes = Vec::new();
for node in declaration.nodes() {
let mut expression = Vec::new();
node_expr(
declaration.harness(),
declaration.namespace(),
node,
&mut expression,
)?;
nodes.push(expression);
}
let mut links = Vec::new();
for link in declaration.links() {
let mut expression = Vec::new();
link_expr(
declaration.harness(),
declaration.namespace(),
link,
&mut expression,
)?;
links.push(expression);
}
let mut seats = Vec::new();
seats.extend(vector(nodes)?);
seats.push(GeneratedToken::alone(','));
seats.extend(vector(links)?);
inner.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
seats,
)?);
inner.push(GeneratedToken::alone('?'));
body.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
inner,
)?);
into.push(GeneratedToken::group(GeneratedDelimiter::Brace, body)?);
Ok(())
}
fn schedule_fn(
declaration: &NetworkDeclaration,
schedule: &ScheduleRow,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
doc_attribute(
&format!("The declared `{}` schedule.", schedule.name()),
into,
)?;
into.push(GeneratedToken::word("pub"));
into.push(GeneratedToken::word("fn"));
into.push(GeneratedToken::word(schedule.name()));
into.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
Vec::new(),
)?);
let mut ok_seat = Vec::new();
direct_path(
declaration.harness(),
&["network", "NetworkSchedule"],
&mut ok_seat,
);
fallible_return(ok_seat, FAULT_ENUM, into);
let mut body = Vec::new();
body.extend(absolute_path(&["core", "result", "Result", "Ok"]));
let mut inner = Vec::new();
direct_path(
declaration.harness(),
&["network", "NetworkSchedule", "declared"],
&mut inner,
);
let mut seats = Vec::new();
direct_path(
declaration.harness(),
&["descriptor", "NamespacedName", "named"],
&mut seats,
);
seats.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
vec![
GeneratedToken::text(declaration.namespace()),
GeneratedToken::alone(','),
GeneratedToken::text(schedule.name()),
],
)?);
seats.push(GeneratedToken::alone('?'));
seats.push(GeneratedToken::alone(','));
let mut disciplines = Vec::new();
for discipline in schedule.disciplines() {
let mut expression = Vec::new();
discipline_expr(
declaration.harness(),
declaration.namespace(),
discipline,
&mut expression,
)?;
disciplines.push(expression);
}
seats.extend(vector(disciplines)?);
inner.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
seats,
)?);
inner.push(GeneratedToken::alone('?'));
body.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
inner,
)?);
into.push(GeneratedToken::group(GeneratedDelimiter::Brace, body)?);
Ok(())
}
fn discipline_expr(
harness: &DirectBinding,
namespace: &str,
discipline: &DisciplineRow,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
direct_path(harness, &["network", "LinkDiscipline", "declared"], into);
let mut seats = Vec::new();
link_expr(harness, namespace, discipline.link(), &mut seats)?;
seats.push(GeneratedToken::alone(','));
let mut faults = Vec::new();
for fault in discipline.faults() {
let mut expression = Vec::new();
fault_expr(harness, fault, &mut expression)?;
faults.push(expression);
}
seats.extend(vector(faults)?);
into.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
seats,
)?);
Ok(())
}
fn fault_expr(
harness: &DirectBinding,
fault: &FaultRow,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
match *fault {
FaultRow::Drop { at } => positional_fault(harness, "DropAt", at, Vec::new(), into),
FaultRow::Duplicate { at } => {
positional_fault(harness, "DuplicateAt", at, Vec::new(), into)
}
FaultRow::Delay { at, by } => {
let mut ticks = vec![
GeneratedToken::alone(','),
GeneratedToken::word("ticks"),
GeneratedToken::alone(':'),
];
direct_path(harness, &["network", "TickSpan", "declared"], &mut ticks);
ticks.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
vec![GeneratedToken::number(u64::from(by))],
)?);
ticks.push(GeneratedToken::alone('?'));
positional_fault(harness, "DelayAt", at, ticks, into)
}
FaultRow::Partition { from, until } => {
direct_path(harness, &["network", "LinkFault", "Partition"], into);
let mut fields = vec![GeneratedToken::word("opens"), GeneratedToken::alone(':')];
tick_expr(harness, from, &mut fields)?;
fields.push(GeneratedToken::alone(','));
fields.push(GeneratedToken::word("heals"));
fields.push(GeneratedToken::alone(':'));
tick_expr(harness, until, &mut fields)?;
into.push(GeneratedToken::group(GeneratedDelimiter::Brace, fields)?);
Ok(())
}
}
}
fn positional_fault(
harness: &DirectBinding,
arm: &str,
at: u32,
extra_fields: Vec<GeneratedToken>,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
direct_path(harness, &["network", "LinkFault", arm], into);
let mut fields = vec![GeneratedToken::word("position"), GeneratedToken::alone(':')];
direct_path(harness, &["network", "SendOrdinal", "at"], &mut fields);
fields.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
vec![GeneratedToken::number(u64::from(at))],
)?);
fields.extend(extra_fields);
into.push(GeneratedToken::group(GeneratedDelimiter::Brace, fields)?);
Ok(())
}
fn tick_expr(
harness: &DirectBinding,
ordinal: u64,
into: &mut Vec<GeneratedToken>,
) -> Result<(), Overflow> {
direct_path(harness, &["network", "Tick", "at"], into);
into.push(GeneratedToken::group(
GeneratedDelimiter::Parenthesis,
vec![GeneratedToken::number(ordinal)],
)?);
Ok(())
}