1use spvirit_codec::spvd_decode::DecodedValue;
4use spvirit_types::*;
5
6use crate::convert::*;
7
8pub fn apply_value_update(nt: &mut NtScalar, val: &DecodedValue, compute_alarms: bool) -> bool {
10 if let DecodedValue::Structure(fields) = val {
11 if let Some((_, inner)) = fields.iter().find(|(name, _)| name == "value") {
12 return apply_value_update(nt, inner, compute_alarms);
13 }
14 }
15 match &mut nt.value {
16 ScalarValue::Bool(current) => {
17 if let Some(v) = decoded_to_bool(val) {
18 *current = v;
19 if compute_alarms {
20 nt.update_alarm_from_value();
21 }
22 return true;
23 }
24 }
25 ScalarValue::I32(current) => {
26 if let Some(v) = decoded_to_i32(val) {
27 *current = v;
28 if compute_alarms {
29 nt.update_alarm_from_value();
30 }
31 return true;
32 }
33 }
34 ScalarValue::F64(current) => {
35 if let Some(v) = decoded_to_f64(val) {
36 *current = v;
37 if compute_alarms {
38 nt.update_alarm_from_value();
39 }
40 return true;
41 }
42 }
43 ScalarValue::Str(current) => {
44 if let Some(v) = decoded_to_string(val) {
45 *current = v;
46 if compute_alarms {
47 nt.update_alarm_from_value();
48 }
49 return true;
50 }
51 }
52 _ => {
53 if let Some(v) = decoded_to_f64(val) {
54 match &mut nt.value {
55 ScalarValue::I8(c) => {
56 *c = v as i8;
57 }
58 ScalarValue::I16(c) => {
59 *c = v as i16;
60 }
61 ScalarValue::I64(c) => {
62 *c = v as i64;
63 }
64 ScalarValue::U8(c) => {
65 *c = v as u8;
66 }
67 ScalarValue::U16(c) => {
68 *c = v as u16;
69 }
70 ScalarValue::U32(c) => {
71 *c = v as u32;
72 }
73 ScalarValue::U64(c) => {
74 *c = v as u64;
75 }
76 ScalarValue::F32(c) => {
77 *c = v as f32;
78 }
79 _ => return false,
80 }
81 if compute_alarms {
82 nt.update_alarm_from_value();
83 }
84 return true;
85 }
86 }
87 }
88 false
89}
90
91pub fn apply_alarm_update(nt: &mut NtScalar, val: &DecodedValue) -> bool {
93 let DecodedValue::Structure(fields) = val else {
94 return false;
95 };
96 let mut changed = false;
97 for (name, v) in fields {
98 match name.as_str() {
99 "severity" => {
100 if let Some(i) = decoded_to_i32(v) {
101 nt.alarm_severity = i;
102 changed = true;
103 }
104 }
105 "status" => {
106 if let Some(i) = decoded_to_i32(v) {
107 nt.alarm_status = i;
108 changed = true;
109 }
110 }
111 "message" => {
112 if let Some(s) = decoded_to_string(v) {
113 nt.alarm_message = s;
114 changed = true;
115 }
116 }
117 _ => {}
118 }
119 }
120 changed
121}
122
123pub fn apply_display_update(nt: &mut NtScalar, val: &DecodedValue) -> bool {
125 let DecodedValue::Structure(fields) = val else {
126 return false;
127 };
128 let mut changed = false;
129 for (name, v) in fields {
130 match name.as_str() {
131 "low" | "limitLow" => {
132 if let Some(f) = decoded_to_f64(v) {
133 nt.display_low = f;
134 changed = true;
135 }
136 }
137 "high" | "limitHigh" => {
138 if let Some(f) = decoded_to_f64(v) {
139 nt.display_high = f;
140 changed = true;
141 }
142 }
143 "description" => {
144 if let Some(s) = decoded_to_string(v) {
145 nt.display_description = s;
146 changed = true;
147 }
148 }
149 "units" => {
150 if let Some(s) = decoded_to_string(v) {
151 nt.units = s;
152 changed = true;
153 }
154 }
155 "precision" => {
156 if let Some(i) = decoded_to_i32(v) {
157 nt.display_precision = i;
158 changed = true;
159 }
160 }
161 "form" => {
162 if let DecodedValue::Structure(form_fields) = v {
163 let mut updated = false;
164 for (fname, fval) in form_fields {
165 match fname.as_str() {
166 "index" => {
167 if let Some(i) = decoded_to_i32(fval) {
168 nt.display_form_index = i;
169 updated = true;
170 }
171 }
172 "choices" => {
173 if let DecodedValue::Array(items) = fval {
174 let mut choices = Vec::new();
175 for item in items {
176 if let DecodedValue::String(s) = item {
177 choices.push(s.clone());
178 }
179 }
180 if !choices.is_empty() {
181 nt.display_form_choices = choices;
182 updated = true;
183 }
184 }
185 }
186 _ => {}
187 }
188 }
189 if updated {
190 changed = true;
191 }
192 }
193 }
194 _ => {}
195 }
196 }
197 changed
198}
199
200pub fn apply_control_update(nt: &mut NtScalar, val: &DecodedValue) -> bool {
202 let DecodedValue::Structure(fields) = val else {
203 return false;
204 };
205 let mut changed = false;
206 for (name, v) in fields {
207 match name.as_str() {
208 "low" | "limitLow" => {
209 if let Some(f) = decoded_to_f64(v) {
210 nt.control_low = f;
211 changed = true;
212 }
213 }
214 "high" | "limitHigh" => {
215 if let Some(f) = decoded_to_f64(v) {
216 nt.control_high = f;
217 changed = true;
218 }
219 }
220 "minStep" => {
221 if let Some(f) = decoded_to_f64(v) {
222 nt.control_min_step = f;
223 changed = true;
224 }
225 }
226 _ => {}
227 }
228 }
229 changed
230}
231
232pub fn apply_scalar_array_put(
234 nt: &mut NtScalarArray,
235 nord: &mut usize,
236 value: &DecodedValue,
237) -> bool {
238 let field_value = match value {
239 DecodedValue::Structure(fields) => fields
240 .iter()
241 .find(|(name, _)| name == "value")
242 .map(|(_, v)| v)
243 .unwrap_or(value),
244 _ => value,
245 };
246 if let Some(next) = decoded_to_scalar_array(field_value, &nt.value) {
247 let changed = nt.value != next;
248 if changed {
249 *nord = next.len();
250 nt.value = next;
251 }
252 return changed;
253 }
254 false
255}
256
257pub fn apply_table_put(nt: &mut NtTable, value: &DecodedValue) -> bool {
259 let DecodedValue::Structure(fields) = value else {
260 return false;
261 };
262 let mut changed = false;
263 for (name, field_value) in fields {
264 match name.as_str() {
265 "labels" => {
266 if let DecodedValue::Array(items) = field_value {
267 let labels: Vec<String> = items.iter().filter_map(decoded_to_string).collect();
268 if !labels.is_empty() && nt.labels != labels {
269 nt.labels = labels;
270 changed = true;
271 }
272 }
273 }
274 "value" => {
275 if let DecodedValue::Structure(cols) = field_value {
276 for (col_name, col_value) in cols {
277 if let Some(col) = nt.columns.iter_mut().find(|c| c.name == *col_name) {
278 if let Some(next) = decoded_to_scalar_array(col_value, &col.values) {
279 if col.values != next {
280 col.values = next;
281 changed = true;
282 }
283 }
284 }
285 }
286 }
287 }
288 "descriptor" => {
289 if let Some(s) = decoded_to_string(field_value) {
290 let next = if s.is_empty() { None } else { Some(s) };
291 if nt.descriptor != next {
292 nt.descriptor = next;
293 changed = true;
294 }
295 }
296 }
297 "alarm" => {
298 if let Some(alarm) = decode_nt_alarm(field_value) {
299 if nt.alarm.as_ref() != Some(&alarm) {
300 nt.alarm = Some(alarm);
301 changed = true;
302 }
303 }
304 }
305 "timeStamp" => {
306 if let Some(ts) = decode_nt_timestamp(field_value) {
307 if nt.time_stamp.as_ref() != Some(&ts) {
308 nt.time_stamp = Some(ts);
309 changed = true;
310 }
311 }
312 }
313 _ => {}
314 }
315 }
316 changed
317}
318
319pub fn apply_ndarray_put(nt: &mut NtNdArray, value: &DecodedValue) -> bool {
321 let DecodedValue::Structure(fields) = value else {
322 return false;
323 };
324 let mut changed = false;
325 for (name, field_value) in fields {
326 match name.as_str() {
327 "value" => {
328 if let Some(next) = decoded_to_scalar_array(field_value, &nt.value) {
329 if nt.value != next {
330 nt.value = next;
331 changed = true;
332 }
333 }
334 }
335 "compressedSize" => {
336 if let Some(v) = decoded_to_i64(field_value) {
337 if nt.compressed_size != v {
338 nt.compressed_size = v;
339 changed = true;
340 }
341 }
342 }
343 "uncompressedSize" => {
344 if let Some(v) = decoded_to_i64(field_value) {
345 if nt.uncompressed_size != v {
346 nt.uncompressed_size = v;
347 changed = true;
348 }
349 }
350 }
351 "uniqueId" => {
352 if let Some(v) = decoded_to_i32(field_value) {
353 if nt.unique_id != v {
354 nt.unique_id = v;
355 changed = true;
356 }
357 }
358 }
359 "codec" => {
360 if let DecodedValue::Structure(codec_fields) = field_value {
361 for (cname, cval) in codec_fields {
362 if cname == "name" {
363 if let Some(s) = decoded_to_string(cval) {
364 if nt.codec.name != s {
365 nt.codec.name = s;
366 changed = true;
367 }
368 }
369 }
370 }
371 }
372 }
373 "dimension" => {
374 if let DecodedValue::Array(items) = field_value {
375 let dims: Vec<NdDimension> = items
376 .iter()
377 .filter_map(|item| {
378 if let DecodedValue::Structure(fs) = item {
379 Some(NdDimension {
380 size: fs
381 .iter()
382 .find(|(n, _)| n == "size")
383 .and_then(|(_, v)| decoded_to_i32(v))
384 .unwrap_or(0),
385 offset: fs
386 .iter()
387 .find(|(n, _)| n == "offset")
388 .and_then(|(_, v)| decoded_to_i32(v))
389 .unwrap_or(0),
390 full_size: fs
391 .iter()
392 .find(|(n, _)| n == "fullSize")
393 .and_then(|(_, v)| decoded_to_i32(v))
394 .unwrap_or(0),
395 binning: fs
396 .iter()
397 .find(|(n, _)| n == "binning")
398 .and_then(|(_, v)| decoded_to_i32(v))
399 .unwrap_or(1),
400 reverse: fs
401 .iter()
402 .find(|(n, _)| n == "reverse")
403 .and_then(|(_, v)| decoded_to_bool(v))
404 .unwrap_or(false),
405 })
406 } else {
407 None
408 }
409 })
410 .collect();
411 if !dims.is_empty() && nt.dimension != dims {
412 nt.dimension = dims;
413 changed = true;
414 }
415 }
416 }
417 "descriptor" => {
418 if let Some(s) = decoded_to_string(field_value) {
419 let next = if s.is_empty() { None } else { Some(s) };
420 if nt.descriptor != next {
421 nt.descriptor = next;
422 changed = true;
423 }
424 }
425 }
426 "alarm" => {
427 if let Some(alarm) = decode_nt_alarm(field_value) {
428 if nt.alarm.as_ref() != Some(&alarm) {
429 nt.alarm = Some(alarm);
430 changed = true;
431 }
432 }
433 }
434 "timeStamp" => {
435 if let Some(ts) = decode_nt_timestamp(field_value) {
436 if nt.time_stamp.as_ref() != Some(&ts) {
437 nt.time_stamp = Some(ts);
438 changed = true;
439 }
440 }
441 }
442 "dataTimeStamp" => {
443 if let Some(ts) = decode_nt_timestamp(field_value) {
444 if nt.data_time_stamp != ts {
445 nt.data_time_stamp = ts;
446 changed = true;
447 }
448 }
449 }
450 "display" => {
451 if let Some(display) = decode_nt_display(field_value) {
452 if nt.display.as_ref() != Some(&display) {
453 nt.display = Some(display);
454 changed = true;
455 }
456 }
457 }
458 "attribute" => {
459 if let DecodedValue::Array(items) = field_value {
460 let attrs: Vec<NtAttribute> = items
461 .iter()
462 .filter_map(|item| {
463 if let DecodedValue::Structure(fs) = item {
464 let attr_name = fs
465 .iter()
466 .find(|(n, _)| n == "name")
467 .and_then(|(_, v)| decoded_to_string(v))
468 .unwrap_or_default();
469 let attr_value = fs
470 .iter()
471 .find(|(n, _)| n == "value")
472 .map(|(_, v)| decoded_to_scalar_value(v))
473 .unwrap_or(ScalarValue::I32(0));
474 let descriptor = fs
475 .iter()
476 .find(|(n, _)| n == "descriptor")
477 .and_then(|(_, v)| decoded_to_string(v))
478 .unwrap_or_default();
479 let source_type = fs
480 .iter()
481 .find(|(n, _)| n == "sourceType")
482 .and_then(|(_, v)| decoded_to_i32(v))
483 .unwrap_or(0);
484 let source = fs
485 .iter()
486 .find(|(n, _)| n == "source")
487 .and_then(|(_, v)| decoded_to_string(v))
488 .unwrap_or_default();
489 Some(NtAttribute {
490 name: attr_name,
491 value: attr_value,
492 descriptor,
493 source_type,
494 source,
495 })
496 } else {
497 None
498 }
499 })
500 .collect();
501 if !attrs.is_empty() && nt.attribute != attrs {
502 nt.attribute = attrs;
503 changed = true;
504 }
505 }
506 }
507 _ => {}
508 }
509 }
510 changed
511}