iota_grpc_types/field/
mod.rs1mod field_mask_tree;
6mod field_mask_util;
7
8pub use field_mask_tree::FieldMaskTree;
9pub use field_mask_util::FieldMaskUtil;
10pub use prost_types::FieldMask;
11
12pub const FIELD_PATH_SEPARATOR: char = ',';
14
15pub const FIELD_SEPARATOR: char = '.';
17
18pub const FIELD_PATH_WILDCARD: &str = "*";
19
20fn is_valid_path(path: &str) -> bool {
21 if path == FIELD_PATH_WILDCARD {
22 return true;
23 }
24
25 path.split(FIELD_SEPARATOR).all(is_valid_path_component)
26}
27
28fn is_valid_path_component(component: &str) -> bool {
37 if component.is_empty() || component == "_" {
38 return false;
39 }
40
41 let component = component.as_bytes();
42
43 if !(component[0].is_ascii_alphabetic() || component[0] == b'_') {
44 return false;
45 }
46
47 for &byte in &component[1..] {
48 if !(byte.is_ascii_alphabetic() || byte.is_ascii_digit() || byte == b'_') {
49 return false;
50 }
51 }
52
53 true
54}
55
56pub trait MessageFields {
57 const FIELDS: &'static [&'static MessageField];
58
59 const ONEOFS: &'static [&'static str] = &[];
67}
68
69pub struct MessageField {
70 pub name: &'static str,
71 pub json_name: &'static str,
72 pub number: i32,
73 pub is_optional: bool,
74 pub is_map: bool,
75 pub message_fields: Option<&'static [&'static MessageField]>,
76}
77
78impl MessageField {
79 pub fn get_optional_message_field_names(&self) -> Vec<String> {
81 let mut names = Vec::new();
82
83 if let Some(nested_fields) = self.message_fields {
85 for field in nested_fields {
86 for nested_name in field.get_optional_message_field_names() {
87 names.push(format!("{}.{}", self.name, nested_name));
88 }
89 }
90 } else if self.is_optional {
91 names.push(self.name.to_string());
93 }
94
95 names
96 }
97}
98
99impl AsRef<str> for MessageField {
100 fn as_ref(&self) -> &str {
101 self.name
102 }
103}
104
105#[doc(hidden)]
106impl MessageField {
107 pub const fn new(name: &'static str) -> Self {
108 Self {
109 name,
110 json_name: "",
111 number: 0,
112 is_optional: false,
113 is_map: false,
114 message_fields: None,
115 }
116 }
117
118 pub const fn with_message_fields(
119 mut self,
120 message_fields: &'static [&'static MessageField],
121 ) -> Self {
122 self.message_fields = Some(message_fields);
123 self
124 }
125
126 pub const fn with_optional(mut self, is_optional: bool) -> Self {
127 self.is_optional = is_optional;
128 self
129 }
130
131 pub const fn with_is_map(mut self, is_map: bool) -> Self {
132 self.is_map = is_map;
133 self
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140
141 #[test]
142 fn test_valid_path_component() {
143 let cases = [
144 ("foo", true),
145 ("_", false),
146 ("", false),
147 ("_abc", true),
148 ("BAR", true),
149 ("foo.bar", false),
150 ];
151
152 for (case, expected) in cases {
153 assert_eq!(is_valid_path_component(case), expected);
154 }
155 }
156
157 #[test]
158 fn test_valid_path() {
159 let cases = [
160 ("*", true),
161 ("**", false),
162 ("foo.bar", true),
163 ("foo.bar.baz", true),
164 ("_", false),
165 (".", false),
166 ("", false),
167 ("_abc", true),
168 ("BAR", true),
169 ];
170
171 for (case, expected) in cases {
172 assert_eq!(is_valid_path(case), expected);
173 }
174 }
175}