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 (bytes.pattern on
12    /// non-UTF-8 input, CEL type mismatch). Maps to protovalidate's runtime
13    /// error.
14    pub runtime_error: Option<String>,
15}
16
17#[derive(Debug, Clone)]
18pub struct Violation {
19    pub field: FieldPath,
20    pub rule: FieldPath,
21    pub rule_id: Cow<'static, str>,
22    pub message: Cow<'static, str>,
23    pub for_key: bool,
24}
25
26#[derive(Debug, Clone, Default)]
27pub struct FieldPath {
28    pub elements: Vec<FieldPathElement>,
29}
30
31#[derive(Debug, Clone, Default)]
32pub struct FieldPathElement {
33    pub field_number: Option<i32>,
34    pub field_name: Option<Cow<'static, str>>,
35    pub field_type: Option<FieldType>,
36    pub key_type: Option<FieldType>,
37    pub value_type: Option<FieldType>,
38    pub subscript: Option<Subscript>,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub enum FieldType {
43    Double,
44    Float,
45    Int64,
46    Uint64,
47    Int32,
48    Fixed64,
49    Fixed32,
50    Bool,
51    String,
52    Group,
53    Message,
54    Bytes,
55    Uint32,
56    Enum,
57    Sfixed32,
58    Sfixed64,
59    Sint32,
60    Sint64,
61}
62
63#[derive(Debug, Clone)]
64pub enum Subscript {
65    Index(u64),
66    BoolKey(bool),
67    IntKey(i64),
68    UintKey(u64),
69    StringKey(Cow<'static, str>),
70}
71
72impl fmt::Display for FieldPath {
73    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
74        let mut first = true;
75        for el in &self.elements {
76            if let Some(name) = &el.field_name {
77                if !first {
78                    f.write_str(".")?;
79                }
80                f.write_str(name)?;
81                first = false;
82            }
83            if let Some(sub) = &el.subscript {
84                match sub {
85                    Subscript::Index(i) => write!(f, "[{i}]")?,
86                    Subscript::BoolKey(b) => write!(f, "[{b}]")?,
87                    Subscript::IntKey(i) => write!(f, "[{i}]")?,
88                    Subscript::UintKey(u) => write!(f, "[{u}]")?,
89                    Subscript::StringKey(s) => write!(f, "[\"{}\"]", s.escape_default())?,
90                }
91            }
92        }
93        Ok(())
94    }
95}
96
97impl fmt::Display for ValidationError {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        let mut first = true;
100        for v in &self.violations {
101            if !first {
102                f.write_str("; ")?;
103            }
104            write!(f, "{}: {} [{}]", v.field, v.message, v.rule_id)?;
105            first = false;
106        }
107        Ok(())
108    }
109}
110
111impl std::error::Error for ValidationError {}