ember_plus/glow/
command.rs1use crate::error::Result;
4use super::root::{GlowCommand, GlowElement, EmberPath};
5use super::element::EmberValue;
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
9pub struct DirFieldMask {
10 pub identifier: bool,
12 pub description: bool,
14 pub tree: bool,
16 pub value: bool,
18 pub connections: bool,
20}
21
22impl DirFieldMask {
23 pub fn all() -> Self {
25 DirFieldMask {
26 identifier: true,
27 description: true,
28 tree: true,
29 value: true,
30 connections: true,
31 }
32 }
33
34 pub fn default_fields() -> Self {
36 DirFieldMask {
37 identifier: true,
38 description: true,
39 tree: false,
40 value: true,
41 connections: false,
42 }
43 }
44
45 pub fn from_bits(bits: i32) -> Self {
47 DirFieldMask {
48 identifier: (bits & 0x01) != 0,
49 description: (bits & 0x02) != 0,
50 tree: (bits & 0x04) != 0,
51 value: (bits & 0x08) != 0,
52 connections: (bits & 0x10) != 0,
53 }
54 }
55
56 pub fn to_bits(&self) -> i32 {
58 let mut bits = 0;
59 if self.identifier { bits |= 0x01; }
60 if self.description { bits |= 0x02; }
61 if self.tree { bits |= 0x04; }
62 if self.value { bits |= 0x08; }
63 if self.connections { bits |= 0x10; }
64 bits
65 }
66}
67
68pub struct CommandBuilder;
70
71impl CommandBuilder {
72 pub fn get_root_directory() -> GlowElement {
74 GlowElement::Command(GlowCommand::GetDirectory)
75 }
76
77 pub fn subscribe() -> GlowElement {
79 GlowElement::Command(GlowCommand::Subscribe)
80 }
81
82 pub fn unsubscribe() -> GlowElement {
84 GlowElement::Command(GlowCommand::Unsubscribe)
85 }
86
87 pub fn invoke(invocation_id: i32, arguments: Vec<EmberValue>) -> GlowElement {
89 GlowElement::Command(GlowCommand::Invoke {
90 invocation_id,
91 arguments,
92 })
93 }
94
95 pub fn get_directory_at_path(path: &EmberPath) -> Vec<GlowElement> {
97 Self::wrap_command_at_path(path, GlowCommand::GetDirectory, None)
98 }
99
100 pub fn get_directory_at_path_with_info(path: &EmberPath, identifier: Option<&str>) -> Vec<GlowElement> {
102 Self::wrap_command_at_path(path, GlowCommand::GetDirectory, identifier)
103 }
104
105 pub fn subscribe_at_path(path: &EmberPath) -> Vec<GlowElement> {
107 Self::wrap_command_at_path(path, GlowCommand::Subscribe, None)
108 }
109
110 pub fn unsubscribe_at_path(path: &EmberPath) -> Vec<GlowElement> {
112 Self::wrap_command_at_path(path, GlowCommand::Unsubscribe, None)
113 }
114
115 fn wrap_command_at_path(path: &EmberPath, command: GlowCommand, identifier: Option<&str>) -> Vec<GlowElement> {
117 if path.is_empty() {
118 return vec![GlowElement::Command(command)];
119 }
120
121 let mut node = super::root::GlowNode::new(0);
123 node.identifier = identifier.map(|s| s.to_string());
124 node.children.push(GlowElement::Command(command));
125 vec![GlowElement::QualifiedNode(path.clone(), node)]
126 }
127
128 pub fn set_value_at_path(path: &EmberPath, value: EmberValue) -> Vec<GlowElement> {
130 if path.is_empty() {
131 return vec![];
132 }
133
134 let param_number = *path.last().unwrap();
135 let parent_path = &path[..path.len() - 1];
136
137 let mut param = super::root::GlowParameter::new(param_number);
138 param.value = Some(value);
139 let param_element = GlowElement::Parameter(param);
140
141 if parent_path.is_empty() {
142 return vec![param_element];
143 }
144
145 let mut current = param_element;
147
148 for &number in parent_path.iter().rev() {
149 let mut node = super::root::GlowNode::new(number);
150 node.children.push(current);
151 current = GlowElement::Node(node);
152 }
153
154 vec![current]
155 }
156
157 pub fn invoke_at_path(
159 path: &EmberPath,
160 invocation_id: i32,
161 arguments: Vec<EmberValue>,
162 ) -> Vec<GlowElement> {
163 if path.is_empty() {
164 return vec![];
165 }
166
167 let mut func = super::root::GlowFunction::new(0);
169 func.children.push(GlowElement::Command(GlowCommand::Invoke {
170 invocation_id,
171 arguments,
172 }));
173 vec![GlowElement::QualifiedFunction(path.clone(), func)]
174 }
175
176 pub fn matrix_connect(
178 path: &EmberPath,
179 target: i32,
180 sources: Vec<i32>,
181 operation: super::element::ConnectionOperation,
182 ) -> Vec<GlowElement> {
183 if path.is_empty() {
184 return vec![];
185 }
186
187 let matrix_number = *path.last().unwrap();
188 let parent_path = &path[..path.len() - 1];
189
190 let connection = super::root::GlowConnection {
191 target,
192 sources,
193 operation: Some(operation),
194 disposition: None,
195 };
196
197 let mut matrix = super::root::GlowMatrix::new(matrix_number);
198 matrix.connections.push(connection);
199 let matrix_element = GlowElement::Matrix(matrix);
200
201 if parent_path.is_empty() {
202 return vec![matrix_element];
203 }
204
205 let mut current = matrix_element;
207
208 for &number in parent_path.iter().rev() {
209 let mut node = super::root::GlowNode::new(number);
210 node.children.push(current);
211 current = GlowElement::Node(node);
212 }
213
214 vec![current]
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 fn test_dirfield_mask() {
224 let mask = DirFieldMask::all();
225 let bits = mask.to_bits();
226 let decoded = DirFieldMask::from_bits(bits);
227
228 assert_eq!(mask.identifier, decoded.identifier);
229 assert_eq!(mask.description, decoded.description);
230 assert_eq!(mask.tree, decoded.tree);
231 assert_eq!(mask.value, decoded.value);
232 assert_eq!(mask.connections, decoded.connections);
233 }
234
235 #[test]
236 fn test_wrap_command_at_path() {
237 let path = vec![0, 1, 2];
238 let elements = CommandBuilder::get_directory_at_path(&path);
239
240 assert_eq!(elements.len(), 1);
241
242 if let GlowElement::Node(n0) = &elements[0] {
244 assert_eq!(n0.number, 0);
245 if let GlowElement::Node(n1) = &n0.children[0] {
246 assert_eq!(n1.number, 1);
247 if let GlowElement::Node(n2) = &n1.children[0] {
248 assert_eq!(n2.number, 2);
249 assert!(matches!(n2.children[0], GlowElement::Command(GlowCommand::GetDirectory)));
250 } else {
251 panic!("Expected Node at level 2");
252 }
253 } else {
254 panic!("Expected Node at level 1");
255 }
256 } else {
257 panic!("Expected Node at level 0");
258 }
259 }
260}