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