1use crate::error::Result;
4use crate::ber::{BerWriter, Tag, TagClass, TagType};
5use crate::glow::{
6 GlowRoot, GlowElement, GlowNode, GlowParameter, GlowFunction,
7 GlowMatrix, GlowConnection, GlowCommand, GlowTemplate,
8 InvocationResult, StreamEntry, EmberPath, EmberValue,
9};
10
11pub struct GlowEncoder;
13
14impl GlowEncoder {
15 pub fn encode(root: &GlowRoot) -> Result<Vec<u8>> {
17 let mut writer = BerWriter::new();
18 Self::encode_root(&mut writer, root)?;
19 Ok(writer.into_bytes())
20 }
21
22 fn encode_root(writer: &mut BerWriter, root: &GlowRoot) -> Result<()> {
24 writer.write_application(0, |w| {
25 if !root.elements.is_empty() {
27 w.write_application(11, |w2| {
28 for element in &root.elements {
29 Self::encode_element(w2, element)?;
30 }
31 Ok(())
32 })?;
33 }
34
35 for result in &root.invocation_results {
37 Self::encode_invocation_result(w, result)?;
38 }
39
40 if !root.streams.is_empty() {
42 w.write_application(6, |w2| {
43 for entry in &root.streams {
44 Self::encode_stream_entry(w2, entry)?;
45 }
46 Ok(())
47 })?;
48 }
49
50 Ok(())
51 })
52 }
53
54 fn encode_element(writer: &mut BerWriter, element: &GlowElement) -> Result<()> {
56 match element {
57 GlowElement::Node(node) => Self::encode_node(writer, node),
58 GlowElement::Parameter(param) => Self::encode_parameter(writer, param),
59 GlowElement::Function(func) => Self::encode_function(writer, func),
60 GlowElement::Matrix(matrix) => Self::encode_matrix(writer, matrix),
61 GlowElement::Command(cmd) => Self::encode_numbered_command(writer, cmd),
62 GlowElement::QualifiedNode(path, node) => Self::encode_qualified_node(writer, path, node),
63 GlowElement::QualifiedParameter(path, param) => Self::encode_qualified_parameter(writer, path, param),
64 GlowElement::QualifiedFunction(path, func) => Self::encode_qualified_function(writer, path, func),
65 GlowElement::QualifiedMatrix(path, matrix) => Self::encode_qualified_matrix(writer, path, matrix),
66 GlowElement::Template(template) => Self::encode_template(writer, template),
67 }
68 }
69
70 fn encode_node(writer: &mut BerWriter, node: &GlowNode) -> Result<()> {
72 writer.write_application(3, |w| {
73 w.write_context_integer(0, node.number as i64)?;
75
76 if node.identifier.is_some() || node.description.is_some()
78 || node.is_root.is_some() || node.is_online.is_some() {
79 w.write_context(1, |w2| {
80 Self::encode_node_contents(w2, node)
81 })?;
82 }
83
84 if !node.children.is_empty() {
86 w.write_context(2, |w2| {
87 w2.write_application(4, |w3| {
88 for child in &node.children {
89 Self::encode_element(w3, child)?;
90 }
91 Ok(())
92 })
93 })?;
94 }
95
96 Ok(())
97 })
98 }
99
100 fn encode_node_contents(writer: &mut BerWriter, node: &GlowNode) -> Result<()> {
102 writer.write_set(|w| {
104 if let Some(id) = &node.identifier {
105 Self::encode_context_utf8string(w, 0, id)?;
106 }
107 if let Some(desc) = &node.description {
108 Self::encode_context_utf8string(w, 1, desc)?;
109 }
110 if let Some(is_root) = node.is_root {
111 Self::encode_context_bool(w, 2, is_root)?;
112 }
113 if let Some(is_online) = node.is_online {
114 Self::encode_context_bool(w, 3, is_online)?;
115 }
116 if let Some(schema) = &node.schema_identifiers {
117 Self::encode_context_utf8string(w, 4, schema)?;
118 }
119 Ok(())
120 })
121 }
122
123 fn encode_parameter(writer: &mut BerWriter, param: &GlowParameter) -> Result<()> {
125 writer.write_application(1, |w| {
126 w.write_context_integer(0, param.number as i64)?;
128
129 w.write_context(1, |w2| {
131 Self::encode_parameter_contents(w2, param)
132 })?;
133
134 if !param.children.is_empty() {
136 w.write_context(2, |w2| {
137 w2.write_application(4, |w3| {
138 for child in ¶m.children {
139 Self::encode_element(w3, child)?;
140 }
141 Ok(())
142 })
143 })?;
144 }
145
146 Ok(())
147 })
148 }
149
150 fn encode_parameter_contents(writer: &mut BerWriter, param: &GlowParameter) -> Result<()> {
152 if let Some(id) = ¶m.identifier {
153 Self::encode_context_string(writer, 0, id)?;
154 }
155 if let Some(desc) = ¶m.description {
156 Self::encode_context_string(writer, 1, desc)?;
157 }
158 if let Some(value) = ¶m.value {
159 Self::encode_context_value(writer, 2, value)?;
160 }
161 if let Some(min) = ¶m.minimum {
162 Self::encode_context_value(writer, 3, min)?;
163 }
164 if let Some(max) = ¶m.maximum {
165 Self::encode_context_value(writer, 4, max)?;
166 }
167 if let Some(access) = param.access {
168 writer.write_context_integer(5, access as i64)?;
169 }
170 if let Some(format) = ¶m.format {
171 Self::encode_context_string(writer, 6, format)?;
172 }
173 if let Some(enumeration) = ¶m.enumeration {
174 Self::encode_context_string(writer, 7, enumeration)?;
175 }
176 if let Some(factor) = param.factor {
177 writer.write_context_integer(8, factor as i64)?;
178 }
179 if let Some(is_online) = param.is_online {
180 Self::encode_context_bool(writer, 9, is_online)?;
181 }
182 if let Some(formula) = ¶m.formula {
183 Self::encode_context_string(writer, 10, formula)?;
184 }
185 if let Some(step) = param.step {
186 writer.write_context_integer(11, step as i64)?;
187 }
188 if let Some(default) = ¶m.default {
189 Self::encode_context_value(writer, 12, default)?;
190 }
191 if let Some(param_type) = param.parameter_type {
192 writer.write_context_integer(13, param_type as i64)?;
193 }
194 if let Some(stream_id) = param.stream_identifier {
195 writer.write_context_integer(14, stream_id as i64)?;
196 }
197 Ok(())
198 }
199
200 fn encode_function(writer: &mut BerWriter, func: &GlowFunction) -> Result<()> {
202 writer.write_application(19, |w| {
203 w.write_context_integer(0, func.number as i64)?;
204
205 w.write_context(1, |w2| {
206 if let Some(id) = &func.identifier {
207 Self::encode_context_string(w2, 0, id)?;
208 }
209 if let Some(desc) = &func.description {
210 Self::encode_context_string(w2, 1, desc)?;
211 }
212 Ok(())
214 })?;
215
216 if !func.children.is_empty() {
217 w.write_context(2, |w2| {
218 w2.write_application(4, |w3| {
219 for child in &func.children {
220 Self::encode_element(w3, child)?;
221 }
222 Ok(())
223 })
224 })?;
225 }
226
227 Ok(())
228 })
229 }
230
231 fn encode_matrix(writer: &mut BerWriter, matrix: &GlowMatrix) -> Result<()> {
233 writer.write_application(13, |w| {
234 w.write_context_integer(0, matrix.number as i64)?;
235
236 w.write_context(1, |w2| {
237 if let Some(id) = &matrix.identifier {
238 Self::encode_context_string(w2, 0, id)?;
239 }
240 if let Some(desc) = &matrix.description {
241 Self::encode_context_string(w2, 1, desc)?;
242 }
243 if let Some(mt) = matrix.matrix_type {
244 w2.write_context_integer(2, mt as i64)?;
245 }
246 if let Some(am) = matrix.addressing_mode {
247 w2.write_context_integer(3, am as i64)?;
248 }
249 if let Some(tc) = matrix.target_count {
250 w2.write_context_integer(4, tc as i64)?;
251 }
252 if let Some(sc) = matrix.source_count {
253 w2.write_context_integer(5, sc as i64)?;
254 }
255 Ok(())
256 })?;
257
258 if !matrix.connections.is_empty() {
260 w.write_context(5, |w2| {
261 for conn in &matrix.connections {
262 Self::encode_connection(w2, conn)?;
263 }
264 Ok(())
265 })?;
266 }
267
268 Ok(())
269 })
270 }
271
272 fn encode_connection(writer: &mut BerWriter, conn: &GlowConnection) -> Result<()> {
274 writer.write_application(16, |w| {
275 w.write_context_integer(0, conn.target as i64)?;
276
277 if !conn.sources.is_empty() {
278 w.write_context(1, |w2| {
279 for &src in &conn.sources {
280 w2.write_integer(src as i64)?;
281 }
282 Ok(())
283 })?;
284 }
285
286 if let Some(op) = conn.operation {
287 w.write_context_integer(2, op as i64)?;
288 }
289
290 if let Some(disp) = conn.disposition {
291 w.write_context_integer(3, disp as i64)?;
292 }
293
294 Ok(())
295 })
296 }
297
298 fn encode_numbered_command(writer: &mut BerWriter, cmd: &GlowCommand) -> Result<()> {
301 writer.write_context(0, |w| {
303 Self::encode_command(w, cmd)
304 })
305 }
306
307 fn encode_command(writer: &mut BerWriter, cmd: &GlowCommand) -> Result<()> {
309 writer.write_application(2, |w| {
310 w.write_context(0, |w2| {
312 w2.write_integer(cmd.number() as i64)
313 })?;
314
315 match cmd {
316 GlowCommand::Invoke { invocation_id, arguments } => {
317 w.write_context(2, |w2| {
319 w2.write_application(22, |w3| {
320 w3.write_context(0, |w4| {
322 w4.write_integer(*invocation_id as i64)
323 })?;
324 w3.write_context(1, |w4| {
326 w4.write_sequence(|w5| {
327 for arg in arguments {
328 Self::encode_value(w5, arg)?;
329 }
330 Ok(())
331 })
332 })?;
333 Ok(())
334 })
335 })?;
336 }
337 _ => {}
338 }
339
340 Ok(())
341 })
342 }
343
344 fn encode_qualified_node(writer: &mut BerWriter, path: &EmberPath, node: &GlowNode) -> Result<()> {
346 writer.write_context(0, |w| {
348 w.write_application(10, |w2| {
349 Self::encode_context_path(w2, 0, path)?;
350
351 w2.write_context(1, |w3| {
354 Self::encode_node_contents(w3, node)
355 })?;
356
357 if !node.children.is_empty() {
358 w2.write_context(2, |w3| {
359 w3.write_application(4, |w4| {
360 for child in &node.children {
361 Self::encode_element(w4, child)?;
362 }
363 Ok(())
364 })
365 })?;
366 }
367
368 Ok(())
369 })
370 })
371 }
372
373 fn encode_qualified_parameter(writer: &mut BerWriter, path: &EmberPath, param: &GlowParameter) -> Result<()> {
375 writer.write_application(9, |w| {
376 Self::encode_context_path(w, 0, path)?;
377
378 w.write_context(1, |w2| {
379 Self::encode_parameter_contents(w2, param)
380 })?;
381
382 Ok(())
383 })
384 }
385
386 fn encode_qualified_function(writer: &mut BerWriter, path: &EmberPath, func: &GlowFunction) -> Result<()> {
388 writer.write_context(0, |w| {
390 w.write_application(20, |w2| {
391 Self::encode_context_path(w2, 0, path)?;
392
393 if func.identifier.is_some() || func.description.is_some() {
395 w2.write_context(1, |w3| {
396 if let Some(id) = &func.identifier {
397 Self::encode_context_string(w3, 0, id)?;
398 }
399 if let Some(desc) = &func.description {
400 Self::encode_context_string(w3, 1, desc)?;
401 }
402 Ok(())
403 })?;
404 }
405
406 if !func.children.is_empty() {
408 w2.write_context(2, |w3| {
409 w3.write_application(4, |w4| {
410 for child in &func.children {
411 Self::encode_element(w4, child)?;
412 }
413 Ok(())
414 })
415 })?;
416 }
417
418 Ok(())
419 })
420 })
421 }
422
423 fn encode_qualified_matrix(writer: &mut BerWriter, path: &EmberPath, matrix: &GlowMatrix) -> Result<()> {
425 writer.write_application(17, |w| {
426 Self::encode_context_path(w, 0, path)?;
427
428 w.write_context(1, |w2| {
429 if let Some(id) = &matrix.identifier {
430 Self::encode_context_string(w2, 0, id)?;
431 }
432 if let Some(desc) = &matrix.description {
433 Self::encode_context_string(w2, 1, desc)?;
434 }
435 Ok(())
436 })?;
437
438 Ok(())
439 })
440 }
441
442 fn encode_template(writer: &mut BerWriter, template: &GlowTemplate) -> Result<()> {
444 writer.write_application(24, |w| {
445 w.write_context_integer(0, template.number as i64)?;
446 if let Some(desc) = &template.description {
447 Self::encode_context_string(w, 2, desc)?;
448 }
449 Ok(())
450 })
451 }
452
453 fn encode_invocation_result(writer: &mut BerWriter, result: &InvocationResult) -> Result<()> {
455 writer.write_application(23, |w| {
456 w.write_context_integer(0, result.invocation_id as i64)?;
457 Self::encode_context_bool(w, 1, result.success)?;
458
459 if !result.result.is_empty() {
460 w.write_context(2, |w2| {
461 for value in &result.result {
462 Self::encode_value(w2, value)?;
463 }
464 Ok(())
465 })?;
466 }
467
468 Ok(())
469 })
470 }
471
472 fn encode_stream_entry(writer: &mut BerWriter, entry: &StreamEntry) -> Result<()> {
474 writer.write_application(5, |w| {
475 w.write_context_integer(0, entry.stream_identifier as i64)?;
476 Self::encode_context_value(w, 1, &entry.value)?;
477 Ok(())
478 })
479 }
480
481 fn encode_context_path(writer: &mut BerWriter, tag: u32, path: &EmberPath) -> Result<()> {
483 let components: Vec<u32> = path.iter().map(|&n| n as u32).collect();
484 writer.write_context(tag, |w| {
485 w.write_relative_oid(&components)
486 })
487 }
488
489 fn encode_context_string(writer: &mut BerWriter, tag: u32, value: &str) -> Result<()> {
491 let tag_obj = Tag::new(TagClass::Context, TagType::Primitive, tag);
492 writer.write_tlv(&tag_obj, value.as_bytes());
493 Ok(())
494 }
495
496 fn encode_context_utf8string(writer: &mut BerWriter, tag: u32, value: &str) -> Result<()> {
499 writer.write_context(tag, |w| {
500 w.write_utf8string(value);
501 Ok(())
502 })
503 }
504
505 fn encode_context_bool(writer: &mut BerWriter, tag: u32, value: bool) -> Result<()> {
507 let tag_obj = Tag::new(TagClass::Context, TagType::Primitive, tag);
508 writer.write_tlv(&tag_obj, &[if value { 0xFF } else { 0x00 }]);
509 Ok(())
510 }
511
512 fn encode_context_value(writer: &mut BerWriter, tag: u32, value: &EmberValue) -> Result<()> {
514 writer.write_context(tag, |w| {
515 Self::encode_value(w, value)
516 })
517 }
518
519 fn encode_value(writer: &mut BerWriter, value: &EmberValue) -> Result<()> {
521 match value {
522 EmberValue::Integer(v) => writer.write_integer(*v),
523 EmberValue::Real(v) => writer.write_real(*v),
524 EmberValue::String(v) => writer.write_utf8_string(v),
525 EmberValue::Boolean(v) => writer.write_boolean(*v),
526 EmberValue::Octets(v) => writer.write_octet_string(v),
527 EmberValue::Null => writer.write_null(),
528 }
529 }
530}