shex_validation/
reason.rs

1use std::fmt::Display;
2
3use shex_ast::{
4    ir::{node_constraint::NodeConstraint, shape::Shape, shape_expr::ShapeExpr},
5    Node,
6};
7
8use crate::ValidatorErrors;
9
10/// Reason represents justifications about why a node conforms to some shape
11#[derive(Debug, Clone)]
12pub enum Reason {
13    NodeConstraintPassed {
14        node: Node,
15        nc: NodeConstraint,
16    },
17    ShapeAndPassed {
18        node: Node,
19        se: ShapeExpr,
20        reasons: Vec<Vec<Reason>>,
21    },
22    ShapeOrPassed {
23        node: Node,
24        shape_expr: ShapeExpr,
25        reasons: Reasons,
26    },
27    ShapeNotPassed {
28        node: Node,
29        shape_expr: ShapeExpr,
30
31        // Errors that are evidences that the negation passess
32        errors_evidences: ValidatorErrors,
33    },
34    ShapePassed {
35        node: Node,
36        shape: Shape,
37    },
38}
39
40impl Display for Reason {
41    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
42        match self {
43            Reason::NodeConstraintPassed { node, nc } => {
44                write!(f, "Node constraint passed. Node: {node}, Constraint: {nc}",)
45            }
46            Reason::ShapeAndPassed { node, se, reasons } => {
47                write!(f, "AND passed. Node {node}, and: {se}, reasons:")?;
48                for reason in reasons {
49                    write!(f, "[")?;
50                    for r in reason {
51                        write!(f, "{r}, ")?;
52                    }
53                    write!(f, "], ")?;
54                }
55                Ok(())
56            }
57            Reason::ShapePassed { node, shape } => {
58                write!(f, "Shape passed. Node {node}, shape: {shape}")
59            }
60            Reason::ShapeOrPassed {
61                node,
62                shape_expr,
63                reasons,
64            } => write!(
65                f,
66                "Shape OR passed. Node {node}, shape: {shape_expr}, reasons: {reasons}"
67            ),
68            Reason::ShapeNotPassed {
69                node,
70                shape_expr,
71                errors_evidences,
72            } => write!(
73                f,
74                "Shape NOT passed. Node {node}, shape: {shape_expr}, errors: {errors_evidences}"
75            ),
76        }
77    }
78}
79
80impl Reason {
81    pub fn as_json(&self) -> serde_json::Value {
82        match self {
83            Reason::NodeConstraintPassed { node, nc } => {
84                serde_json::json!({
85                    "type": "NodeConstraintPassed",
86                    "node": node.to_string(),
87                    "constraint": nc.to_string()
88                })
89            }
90            Reason::ShapeAndPassed { node, se, reasons } => {
91                serde_json::json!({
92                    "type": "ShapeAndPassed",
93                    "node": node.to_string(),
94                    "shape_expr": se.to_string(),
95                    "reasons": reasons.iter().map(|r| {
96                        r.iter().map(|reason| reason.as_json()).collect::<Vec<_>>()
97                    }).collect::<Vec<_>>()
98                })
99            }
100            Reason::ShapePassed { node, shape } => {
101                serde_json::json!({
102                    "type": "ShapePassed",
103                    "node": node.to_string(),
104                    "shape": shape.to_string()
105                })
106            }
107            Reason::ShapeOrPassed {
108                node,
109                shape_expr,
110                reasons: _,
111            } => {
112                serde_json::json!({
113                    "type": "ShapeOrPassed",
114                    "node": node.to_string(),
115                    "shape_expr": shape_expr.to_string(),
116                    /*"reasons": reasons.iter().map(|reason| {
117                        reason.as_json()
118                    }).collect::<Vec<_>>()*/
119                })
120            }
121            Reason::ShapeNotPassed {
122                node,
123                shape_expr,
124                errors_evidences: _,
125            } => {
126                serde_json::json!({
127                    "type": "ShapeNotPassed",
128                    "node": node.to_string(),
129                    "shape_expr": shape_expr.to_string(),
130                    /*"errors_evidences": errors_evidences.iter().map(|reason| {
131                        reason.as_json()
132                    }).collect::<Vec<_>>() */
133                })
134            }
135        }
136    }
137}
138
139#[derive(Debug, Clone)]
140pub struct Reasons {
141    reasons: Vec<Reason>,
142}
143
144impl Reasons {
145    pub fn new(reasons: Vec<Reason>) -> Reasons {
146        Reasons { reasons }
147    }
148}
149
150impl Display for Reasons {
151    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
152        for reason in self.reasons.iter() {
153            writeln!(f, "  {reason}")?;
154        }
155        Ok(())
156    }
157}