1mod field_mask_tree;
2mod field_mask_util;
3
4pub use field_mask_tree::FieldMaskTree;
5pub use field_mask_util::FieldMaskUtil;
6pub use prost_types::FieldMask;
7
8pub const FIELD_PATH_SEPARATOR: char = ',';
10
11pub const FIELD_SEPARATOR: char = '.';
13
14pub const FIELD_PATH_WILDCARD: &str = "*";
15
16fn is_valid_path(path: &str) -> bool {
17 if path == FIELD_PATH_WILDCARD {
18 return true;
19 }
20
21 path.split(FIELD_SEPARATOR).all(is_valid_path_component)
22}
23
24fn is_valid_path_component(component: &str) -> bool {
33 if component.is_empty() || component == "_" {
34 return false;
35 }
36
37 let component = component.as_bytes();
38
39 if !(component[0].is_ascii_alphabetic() || component[0] == b'_') {
40 return false;
41 }
42
43 for &byte in &component[1..] {
44 if !(byte.is_ascii_alphabetic() || byte.is_ascii_digit() || byte == b'_') {
45 return false;
46 }
47 }
48
49 true
50}
51
52pub trait MessageFields {
53 const FIELDS: &'static [&'static MessageField];
54}
55
56pub struct MessageField {
57 pub name: &'static str,
58 pub json_name: &'static str,
59 pub number: i32,
60 pub message_fields: Option<&'static [&'static MessageField]>,
61}
62
63impl AsRef<str> for MessageField {
64 fn as_ref(&self) -> &str {
65 self.name
66 }
67}
68
69#[doc(hidden)]
70impl MessageField {
71 pub const fn new(name: &'static str) -> Self {
72 Self {
73 name,
74 json_name: "",
75 number: 0,
76 message_fields: None,
77 }
78 }
79
80 pub const fn with_message_fields(
81 mut self,
82 message_fields: &'static [&'static MessageField],
83 ) -> Self {
84 self.message_fields = Some(message_fields);
85 self
86 }
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn test_valid_path_component() {
95 let cases = [
96 ("foo", true),
97 ("_", false),
98 ("", false),
99 ("_abc", true),
100 ("BAR", true),
101 ("foo.bar", false),
102 ];
103
104 for (case, expected) in cases {
105 assert_eq!(is_valid_path_component(case), expected);
106 }
107 }
108
109 #[test]
110 fn test_valid_path() {
111 let cases = [
112 ("*", true),
113 ("**", false),
114 ("foo.bar", true),
115 ("foo.bar.baz", true),
116 ("_", false),
117 (".", false),
118 ("", false),
119 ("_abc", true),
120 ("BAR", true),
121 ];
122
123 for (case, expected) in cases {
124 assert_eq!(is_valid_path(case), expected);
125 }
126 }
127}