1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use crate::protovalidate::{FieldPath, FieldPathElement, Violation, Violations};
impl FieldPath {
/// Returns the last member in the elements list, if the list is not empty.
pub fn last_field(&self) -> Option<&FieldPathElement> {
if let Some(last_field) = self.elements.last() {
return Some(last_field);
}
None
}
/// Returns the second last member in the elements list, if the list is not empty.
pub fn parent_field(&self) -> Option<&FieldPathElement> {
let second_last = self.elements.get(self.elements.len().wrapping_sub(2));
match second_last {
Some(el) => Some(el),
None => None,
}
}
/// Checks if the elements list is empty or not.
pub fn has_fields(&self) -> bool {
self.last_field().is_some()
}
/// Returns the name of the last member in the elements list, if there is one.
pub fn last_field_name(&self) -> Option<&str> {
self.last_field().map(|f| f.field_name())
}
/// Searches for a FieldPathElement by name in the elements list.
pub fn get_field(&self, name: &str) -> Option<&FieldPathElement> {
self
.elements
.iter()
.find(|&field| field.field_name() == name)
}
/// Returns a vector with the names from each element in the list.
pub fn field_path(&self) -> Vec<String> {
let mut path: Vec<String> = Vec::new();
for field in self.elements.iter() {
path.push(field.field_name().to_string());
if let Some(key) = &field.subscript {
path.push(key.to_string());
}
}
path
}
/// Returns all of the names from each path element, joined by a dot (e.g. `person.friend.0.address.street_name`)
pub fn field_path_str(&self) -> String {
self.field_path().join(".")
}
}
impl Violations {
/// Searches for a violation with a specific rule id.
pub fn violation_by_rule_id(&self, rule_id: &str) -> Option<&Violation> {
self.violations.iter().find(|v| v.rule_id() == rule_id)
}
}
impl Violation {
/// Returns the last member in the elements list, if there is one.
pub fn last_field(&self) -> Option<&FieldPathElement> {
if let Some(fields) = &self.field {
return fields.last_field();
}
None
}
/// Returns the second last member in the elements list, if there is one.
pub fn parent_field(&self) -> Option<&FieldPathElement> {
if let Some(fields) = &self.field {
return fields.parent_field();
}
None
}
/// Searches for a field in the FieldPath list with a specific name.
pub fn get_field(&self, name: &str) -> Option<&FieldPathElement> {
if let Some(fields) = &self.field {
return fields.get_field(name);
}
None
}
/// If the FieldPath is present, it will return the list of the names for each path element.
pub fn field_path(&self) -> Option<Vec<String>> {
if let Some(fields) = &self.field {
return Some(fields.field_path());
}
None
}
/// Returns the element names composing the violation's rule, like ["string", "max_len"].
pub fn rule_path(&self) -> Option<Vec<String>> {
if let Some(rules) = &self.rule {
return Some(rules.field_path());
}
None
}
/// If there is a FieldPath, it returns the path elements' names, joined by a dot (e.g. `person.friend.0.address.street_name`).
pub fn field_path_str(&self) -> Option<String> {
if let Some(fields) = &self.field {
return Some(fields.field_path_str());
}
None
}
/// If a rule path is defined, it returns the rule path segments for this violation, joined by a dot (e.g. `map.keys.string.min_len`)
pub fn rule_path_str(&self) -> Option<String> {
if let Some(rules) = &self.rule {
return Some(rules.field_path_str());
}
None
}
/// Checks whether this violation has a FieldPath or not. This may not be the case when a violation is triggered by a rule defined with (buf.validate.message).cel in a message
pub fn has_fields(&self) -> bool {
self.last_field().is_some()
}
/// Checks if the list of FieldPathElements contains a field with a particular name.
pub fn has_field_by_name(&self, name: &str) -> bool {
self.get_field(name).is_some()
}
/// If a list of path elements is defined, it returns the name of the invalid field (the last field in the list of path elements)
pub fn field_name(&self) -> Option<&str> {
self.last_field().map(|f| f.field_name())
}
}