sui_rpc/field/
field_mask_tree.rs1use super::is_valid_path;
2use super::FieldMaskUtil;
3use super::FIELD_PATH_SEPARATOR;
4use super::FIELD_PATH_WILDCARD;
5use super::FIELD_SEPARATOR;
6
7use prost_types::FieldMask;
8use std::collections::BTreeMap;
9
10#[derive(Clone, Debug, Default)]
11pub struct FieldMaskTree {
12 wildcard: bool,
13 root: Node,
14}
15
16#[derive(Clone, Debug, Default)]
17struct Node {
18 children: BTreeMap<String, Node>,
19}
20
21impl FieldMaskTree {
22 pub fn new_wildcard() -> Self {
23 Self {
24 wildcard: true,
25 root: Default::default(),
26 }
27 }
28
29 pub fn add_field_path(&mut self, path: &str) -> &mut Self {
30 if self.wildcard || !is_valid_path(path) {
31 return self;
32 }
33
34 if path == FIELD_PATH_WILDCARD {
35 self.wildcard = true;
36 self.root.children.clear();
37 return self;
38 }
39
40 let root = std::ptr::from_ref(&self.root);
41 let mut node = &mut self.root;
42 let mut create_new_branch = false;
43 for component in path.split(FIELD_SEPARATOR) {
44 if !create_new_branch && !std::ptr::eq(root, node) && node.children.is_empty() {
45 return self;
46 }
47
48 node = node
49 .children
50 .entry(component.to_owned())
51 .or_insert_with(|| {
52 create_new_branch = true;
53 Node::default()
54 });
55 }
56
57 node.children.clear();
58 self
59 }
60
61 pub fn from_field_mask(mask: &FieldMask) -> Self {
62 let mut tree = Self::default();
63 for path in &mask.paths {
64 tree.add_field_path(path);
65 }
66 tree
67 }
68
69 pub fn to_field_mask(&self) -> FieldMask {
70 if self.root.children.is_empty() {
71 return FieldMask::default();
72 }
73
74 let mut paths = Vec::new();
75 Self::collect_field_paths(&self.root, &mut String::new(), &mut paths);
76 FieldMask { paths }
77 }
78
79 fn collect_field_paths(node: &Node, path: &mut String, paths: &mut Vec<String>) {
80 if node.children.is_empty() {
81 paths.push(path.clone());
82 return;
83 }
84
85 let parent_path_len = path.len();
86 for (part, child) in node.children.iter() {
87 if path.is_empty() {
88 path.push_str(part);
89 } else {
90 path.push(FIELD_SEPARATOR);
91 path.push_str(part);
92 };
93 Self::collect_field_paths(child, path, paths);
94 path.truncate(parent_path_len);
95 }
96 }
97
98 pub fn contains<P: AsRef<str>>(&self, path: P) -> bool {
113 let path = path.as_ref();
114
115 if path.is_empty() {
116 return false;
117 }
118
119 if self.wildcard {
120 return true;
121 }
122
123 let mut node = &self.root;
124 for component in path.split(FIELD_SEPARATOR) {
125 if !std::ptr::eq(node, &self.root) && node.children.is_empty() {
128 return true;
129 }
130
131 if let Some(child) = node.children.get(component) {
132 node = child;
133 } else {
134 return false;
135 }
136 }
137
138 true
141 }
142
143 pub fn subtree<P: AsRef<str>>(&self, path: P) -> Option<Self> {
144 let path = path.as_ref();
145
146 if path.is_empty() {
147 return None;
148 }
149
150 if self.wildcard {
151 return Some(self.clone());
152 }
153
154 let mut node = &self.root;
155 for component in path.split(FIELD_SEPARATOR) {
156 if let Some(child) = node.children.get(component) {
157 node = child;
158 } else {
159 return None;
160 }
161 }
162
163 if std::ptr::eq(node, &self.root) {
164 None
165 } else {
166 Some(Self {
167 wildcard: node.children.is_empty(),
168 root: node.clone(),
169 })
170 }
171 }
172}
173
174impl From<FieldMask> for FieldMaskTree {
175 fn from(mask: FieldMask) -> Self {
176 Self::from_field_mask(&mask)
177 }
178}
179
180impl From<FieldMaskTree> for FieldMask {
181 fn from(tree: FieldMaskTree) -> Self {
182 tree.to_field_mask()
183 }
184}
185
186impl std::fmt::Display for FieldMaskTree {
187 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
188 FieldMaskUtil::display(&self.to_field_mask()).fmt(f)
189 }
190}
191
192impl std::str::FromStr for FieldMaskTree {
193 type Err = std::convert::Infallible;
194
195 fn from_str(s: &str) -> Result<Self, Self::Err> {
196 let mut tree = Self::default();
197
198 for path in s.split(FIELD_PATH_SEPARATOR) {
199 tree.add_field_path(path);
200 }
201
202 Ok(tree)
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209
210 #[test]
211 fn test_add_field_path() {
212 let mut tree = FieldMaskTree::default();
213
214 assert!(tree.to_string().is_empty());
215 tree.add_field_path("");
216 assert!(tree.to_string().is_empty());
217
218 tree.add_field_path("foo");
219 assert_eq!(tree.to_string(), "foo");
220 tree.add_field_path("foo");
222 assert_eq!(tree.to_string(), "foo");
223
224 tree.add_field_path("bar.baz");
225 assert_eq!(tree.to_string(), "bar.baz,foo");
226
227 tree.add_field_path("foo.bar");
229 assert_eq!(tree.to_string(), "bar.baz,foo");
230
231 tree.add_field_path("bar.quz");
233 assert_eq!(tree.to_string(), "bar.baz,bar.quz,foo");
234
235 tree.add_field_path("bar");
237 assert_eq!(tree.to_string(), "bar,foo");
238 }
239
240 #[test]
241 fn test_contains() {
242 let mut tree = FieldMaskTree::default();
243
244 assert!(!tree.contains("foo"));
245 assert!(!tree.contains("foo.bar"));
246
247 tree.add_field_path("foo.bar");
248
249 assert!(tree.contains("foo"));
250 assert!(tree.contains("foo.bar"));
251 assert!(!tree.contains("foo.baz"));
252 assert!(!tree.contains("foobar"));
253 }
254}