Skip to main content

protovalidate_buffa/
error.rs

1use std::{borrow::Cow, fmt};
2
3#[derive(Debug, Clone, Default)]
4pub struct ValidationError {
5    pub violations: Vec<Violation>,
6    /// Non-empty when the generated validator detected at code-gen time that
7    /// a rule was malformed (mismatched rule/field type, malformed oneof
8    /// spec, CEL referencing a non-existent field). Maps to protovalidate's
9    /// compilation error.
10    pub compile_error: Option<String>,
11    /// Non-empty when a rule's runtime precondition failed. Examples:
12    /// `bytes.pattern` applied to non-UTF-8 input; a CEL expression
13    /// that the plugin transpiler classified as always-runtime-error
14    /// (e.g. `dyn(this).<unknown_field>`); a CEL expression the
15    /// transpiler couldn't compile (the unsupported construct is
16    /// inlined into the error message). Maps to protovalidate's
17    /// runtime error.
18    pub runtime_error: Option<String>,
19}
20
21#[derive(Debug, Clone)]
22pub struct Violation {
23    pub field: FieldPath,
24    pub rule: FieldPath,
25    pub rule_id: Cow<'static, str>,
26    pub message: Cow<'static, str>,
27    pub for_key: bool,
28}
29
30#[derive(Debug, Clone, Default)]
31pub struct FieldPath {
32    pub elements: Vec<FieldPathElement>,
33}
34
35#[derive(Debug, Clone, Default)]
36pub struct FieldPathElement {
37    pub field_number: Option<i32>,
38    pub field_name: Option<Cow<'static, str>>,
39    pub field_type: Option<FieldType>,
40    pub key_type: Option<FieldType>,
41    pub value_type: Option<FieldType>,
42    pub subscript: Option<Subscript>,
43}
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum FieldType {
47    Double,
48    Float,
49    Int64,
50    Uint64,
51    Int32,
52    Fixed64,
53    Fixed32,
54    Bool,
55    String,
56    Group,
57    Message,
58    Bytes,
59    Uint32,
60    Enum,
61    Sfixed32,
62    Sfixed64,
63    Sint32,
64    Sint64,
65}
66
67#[derive(Debug, Clone)]
68pub enum Subscript {
69    Index(u64),
70    BoolKey(bool),
71    IntKey(i64),
72    UintKey(u64),
73    StringKey(Cow<'static, str>),
74}
75
76impl fmt::Display for FieldPath {
77    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78        let mut first = true;
79        for el in &self.elements {
80            if let Some(name) = &el.field_name {
81                if !first {
82                    f.write_str(".")?;
83                }
84                f.write_str(name)?;
85                first = false;
86            }
87            if let Some(sub) = &el.subscript {
88                match sub {
89                    Subscript::Index(i) => write!(f, "[{i}]")?,
90                    Subscript::BoolKey(b) => write!(f, "[{b}]")?,
91                    Subscript::IntKey(i) => write!(f, "[{i}]")?,
92                    Subscript::UintKey(u) => write!(f, "[{u}]")?,
93                    Subscript::StringKey(s) => write!(f, "[\"{}\"]", s.escape_default())?,
94                }
95            }
96        }
97        Ok(())
98    }
99}
100
101impl fmt::Display for ValidationError {
102    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103        let mut first = true;
104        for v in &self.violations {
105            if !first {
106                f.write_str("; ")?;
107            }
108            write!(f, "{}: {} [{}]", v.field, v.message, v.rule_id)?;
109            first = false;
110        }
111        Ok(())
112    }
113}
114
115impl std::error::Error for ValidationError {}