1use frp_domain::{Block, BlockSchema, Port, PortDirection};
4
5use crate::error::WeaveError;
6
7pub struct Validator;
9
10impl Validator {
11 pub fn validate_connection(output: &Port, input: &Port) -> Result<(), WeaveError> {
18 if output.direction != PortDirection::Output {
19 return Err(WeaveError::IncompatiblePorts {
20 from: output.name.clone(),
21 to: input.name.clone(),
22 });
23 }
24 if input.direction != PortDirection::Input {
25 return Err(WeaveError::IncompatiblePorts {
26 from: output.name.clone(),
27 to: input.name.clone(),
28 });
29 }
30 if !output.type_sig.is_compatible_with(&input.type_sig) {
31 return Err(WeaveError::IncompatiblePorts {
32 from: format!("{} ({:?})", output.name, output.type_sig),
33 to: format!("{} ({:?})", input.name, input.type_sig),
34 });
35 }
36 Ok(())
37 }
38
39 pub fn validate_block(block: &Block, schema: &BlockSchema) -> Result<(), WeaveError> {
41 if block.atoms.is_empty() {
42 return Err(WeaveError::ValidationFailed(
43 "block must contain at least one atom".to_string(),
44 ));
45 }
46 schema
47 .validate()
48 .map_err(|e| WeaveError::ValidationFailed(e.to_string()))?;
49 Ok(())
50 }
51}
52
53#[cfg(test)]
54mod tests {
55 use super::*;
56 use frp_domain::Port;
57 use frp_plexus::{PortId, TypeSig};
58
59 fn in_port(id: u64, name: &str, ty: TypeSig) -> Port {
60 Port::new_input(PortId::new(id), name.to_string(), ty)
61 }
62
63 fn out_port(id: u64, name: &str, ty: TypeSig) -> Port {
64 Port::new_output(PortId::new(id), name.to_string(), ty)
65 }
66
67 #[test]
68 fn compatible_any_types_pass() {
69 let out = out_port(1, "o", TypeSig::Any);
70 let inp = in_port(2, "i", TypeSig::Int);
71 Validator::validate_connection(&out, &inp).unwrap();
72 }
73
74 #[test]
75 fn matching_concrete_types_pass() {
76 let out = out_port(1, "o", TypeSig::Int);
77 let inp = in_port(2, "i", TypeSig::Int);
78 Validator::validate_connection(&out, &inp).unwrap();
79 }
80
81 #[test]
82 fn mismatched_types_fail() {
83 let out = out_port(1, "o", TypeSig::Int);
84 let inp = in_port(2, "i", TypeSig::Bool);
85 let err = Validator::validate_connection(&out, &inp).unwrap_err();
86 assert!(matches!(err, WeaveError::IncompatiblePorts { .. }));
87 }
88
89 #[test]
90 fn wrong_directions_fail() {
91 let out = in_port(1, "o", TypeSig::Any);
93 let inp = in_port(2, "i", TypeSig::Any);
94 let err = Validator::validate_connection(&out, &inp).unwrap_err();
95 assert!(matches!(err, WeaveError::IncompatiblePorts { .. }));
96 }
97}