pub mod boundary;
pub mod failover;
pub mod layout;
pub mod memory_class_pass;
pub mod obs_pass;
pub mod ownership;
pub mod queue;
pub mod reactive;
pub mod semantic_lane;
pub mod traits;
pub mod trust_zone;
pub use boundary::BoundaryLegalityPass;
pub use failover::FailoverLegalityPass;
pub use layout::LayoutLegalityPass;
pub use memory_class_pass::MemoryClassCompatibilityPass;
pub use obs_pass::ObsAnnotationPass;
pub use ownership::OwnershipLegalityPass;
pub use queue::QueueCapabilityPass;
pub use reactive::{LaneLegalityPass, ReactiveInterfacePass};
pub use semantic_lane::SemanticLanePass;
pub use trust_zone::TrustZonePass;
pub use traits::{Diagnostic, Severity, ValidationPass, ValidationReport};
use vil_ir::core::WorkflowIR;
#[derive(Default)]
pub struct Validator {
passes: Vec<Box<dyn ValidationPass>>,
}
impl Validator {
pub fn new() -> Self {
Self::default()
}
pub fn standard() -> Self {
let mut v = Self::new();
v.add_pass(LayoutLegalityPass);
v.add_pass(BoundaryLegalityPass);
v.add_pass(QueueCapabilityPass);
v.add_pass(OwnershipLegalityPass);
v.add_pass(LaneLegalityPass);
v.add_pass(ReactiveInterfacePass);
v.add_pass(SemanticLanePass);
v.add_pass(FailoverLegalityPass);
v.add_pass(TrustZonePass);
v.add_pass(ObsAnnotationPass);
v.add_pass(MemoryClassCompatibilityPass);
v
}
pub fn add_pass<P: ValidationPass + 'static>(&mut self, pass: P) {
self.passes.push(Box::new(pass));
}
pub fn validate(&self, ir: &WorkflowIR) -> ValidationReport {
let mut global_report = ValidationReport::new();
for pass in &self.passes {
let pass_report = pass.run(ir);
global_report.merge(pass_report);
}
global_report
}
}
#[cfg(test)]
mod tests {
use super::*;
use vil_ir::builder::{InterfaceBuilder, MessageBuilder, ProcessBuilder, WorkflowBuilder};
use vil_types::{CleanupPolicy, LayoutProfile, QueueKind, TransferMode};
#[test]
fn test_valid_ir() {
let ir = WorkflowBuilder::new("ValidFlow")
.add_message(
MessageBuilder::new("Msg")
.layout(LayoutProfile::Relative)
.build(),
)
.add_interface(
InterfaceBuilder::new("Iface")
.out_port("tx", "Msg")
.queue(QueueKind::Spsc, 10)
.done()
.in_port("rx", "Msg")
.queue(QueueKind::Spsc, 10)
.done()
.build(),
)
.add_process(
ProcessBuilder::new("A", "Iface")
.cleanup(CleanupPolicy::ReclaimOrphans)
.build(),
)
.add_process(
ProcessBuilder::new("B", "Iface")
.cleanup(CleanupPolicy::ReclaimOrphans)
.build(),
)
.route("A", "tx", "B", "rx", TransferMode::LoanWrite)
.build();
let validator = Validator::standard();
let report = validator.validate(&ir);
assert!(!report.has_errors());
assert_eq!(report.diagnostics.len(), 0);
}
#[test]
fn test_invalid_layout() {
let ir = WorkflowBuilder::new("BadLayoutFlow")
.add_message(
MessageBuilder::new("ExternalMsg")
.layout(LayoutProfile::External)
.build(),
)
.add_interface(
InterfaceBuilder::new("Iface")
.out_port("tx", "ExternalMsg")
.queue(QueueKind::Spsc, 10)
.done()
.in_port("rx", "ExternalMsg")
.queue(QueueKind::Spsc, 10)
.done()
.build(),
)
.add_process(ProcessBuilder::new("A", "Iface").build())
.add_process(ProcessBuilder::new("B", "Iface").build())
.route("A", "tx", "B", "rx", TransferMode::PublishOffset)
.build();
let validator = Validator::standard();
let report = validator.validate(&ir);
assert!(report.has_errors());
assert!(report.diagnostics.iter().any(|d| d.code == "E-LAYOUT-02"));
}
#[test]
fn test_invalid_queue() {
let ir = WorkflowBuilder::new("BadQueueFlow")
.add_message(
MessageBuilder::new("Msg")
.layout(LayoutProfile::Relative)
.build(),
)
.add_interface(
InterfaceBuilder::new("Iface")
.out_port("tx", "Msg")
.queue(QueueKind::Spsc, 10)
.done()
.in_port("rx", "Msg")
.queue(QueueKind::Spsc, 10)
.done()
.build(),
)
.add_process(ProcessBuilder::new("A", "Iface").build())
.add_process(ProcessBuilder::new("B", "Iface").build())
.add_process(ProcessBuilder::new("C", "Iface").build())
.route("A", "tx", "B", "rx", TransferMode::LoanWrite)
.route("A", "tx", "C", "rx", TransferMode::LoanWrite)
.build();
let validator = Validator::standard();
let report = validator.validate(&ir);
assert!(report.has_errors());
assert!(report.diagnostics.iter().any(|d| d.code == "E-QUEUE-01"));
}
}