sui_rpc/field/
field_mask_tree.rs1use super::FIELD_PATH_SEPARATOR;
2use super::FIELD_PATH_WILDCARD;
3use super::FIELD_SEPARATOR;
4use super::FieldMaskUtil;
5use super::is_valid_path;
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 node = node.children.get(component)?;
157 }
158
159 if std::ptr::eq(node, &self.root) {
160 None
161 } else {
162 Some(Self {
163 wildcard: node.children.is_empty(),
164 root: node.clone(),
165 })
166 }
167 }
168}
169
170impl From<FieldMask> for FieldMaskTree {
171 fn from(mask: FieldMask) -> Self {
172 Self::from_field_mask(&mask)
173 }
174}
175
176impl From<FieldMaskTree> for FieldMask {
177 fn from(tree: FieldMaskTree) -> Self {
178 tree.to_field_mask()
179 }
180}
181
182impl std::fmt::Display for FieldMaskTree {
183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 FieldMaskUtil::display(&self.to_field_mask()).fmt(f)
185 }
186}
187
188impl std::str::FromStr for FieldMaskTree {
189 type Err = std::convert::Infallible;
190
191 fn from_str(s: &str) -> Result<Self, Self::Err> {
192 let mut tree = Self::default();
193
194 for path in s.split(FIELD_PATH_SEPARATOR) {
195 tree.add_field_path(path);
196 }
197
198 Ok(tree)
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 fn test_add_field_path() {
208 let mut tree = FieldMaskTree::default();
209
210 assert!(tree.to_string().is_empty());
211 tree.add_field_path("");
212 assert!(tree.to_string().is_empty());
213
214 tree.add_field_path("foo");
215 assert_eq!(tree.to_string(), "foo");
216 tree.add_field_path("foo");
218 assert_eq!(tree.to_string(), "foo");
219
220 tree.add_field_path("bar.baz");
221 assert_eq!(tree.to_string(), "bar.baz,foo");
222
223 tree.add_field_path("foo.bar");
225 assert_eq!(tree.to_string(), "bar.baz,foo");
226
227 tree.add_field_path("bar.quz");
229 assert_eq!(tree.to_string(), "bar.baz,bar.quz,foo");
230
231 tree.add_field_path("bar");
233 assert_eq!(tree.to_string(), "bar,foo");
234 }
235
236 #[test]
237 fn test_contains() {
238 let mut tree = FieldMaskTree::default();
239
240 assert!(!tree.contains("foo"));
241 assert!(!tree.contains("foo.bar"));
242
243 tree.add_field_path("foo.bar");
244
245 assert!(tree.contains("foo"));
246 assert!(tree.contains("foo.bar"));
247 assert!(!tree.contains("foo.baz"));
248 assert!(!tree.contains("foobar"));
249 }
250}