1use spvirit_codec::spvd_decode::DecodedValue;
4use spvirit_types::{ScalarArrayValue, ScalarValue};
5
6pub fn decoded_to_bool(val: &DecodedValue) -> Option<bool> {
7 match val {
8 DecodedValue::Boolean(v) => Some(*v),
9 DecodedValue::Int8(v) => Some(*v != 0),
10 DecodedValue::Int16(v) => Some(*v != 0),
11 DecodedValue::Int32(v) => Some(*v != 0),
12 DecodedValue::Int64(v) => Some(*v != 0),
13 DecodedValue::UInt8(v) => Some(*v != 0),
14 DecodedValue::UInt16(v) => Some(*v != 0),
15 DecodedValue::UInt32(v) => Some(*v != 0),
16 DecodedValue::UInt64(v) => Some(*v != 0),
17 DecodedValue::Float32(v) => Some(*v != 0.0),
18 DecodedValue::Float64(v) => Some(*v != 0.0),
19 _ => None,
20 }
21}
22
23pub fn decoded_to_i8(val: &DecodedValue) -> Option<i8> {
24 decoded_to_i64(val).and_then(|v| i8::try_from(v).ok())
25}
26
27pub fn decoded_to_i16(val: &DecodedValue) -> Option<i16> {
28 decoded_to_i64(val).and_then(|v| i16::try_from(v).ok())
29}
30
31pub fn decoded_to_i32(val: &DecodedValue) -> Option<i32> {
32 match val {
33 DecodedValue::Int8(v) => Some(*v as i32),
34 DecodedValue::Int16(v) => Some(*v as i32),
35 DecodedValue::Int32(v) => Some(*v),
36 DecodedValue::Int64(v) => Some(*v as i32),
37 DecodedValue::UInt8(v) => Some(*v as i32),
38 DecodedValue::UInt16(v) => Some(*v as i32),
39 DecodedValue::UInt32(v) => Some(*v as i32),
40 DecodedValue::UInt64(v) => Some(*v as i32),
41 DecodedValue::Boolean(v) => Some(if *v { 1 } else { 0 }),
42 DecodedValue::Float32(v) => Some(*v as i32),
43 DecodedValue::Float64(v) => Some(*v as i32),
44 _ => None,
45 }
46}
47
48pub fn decoded_to_i64(val: &DecodedValue) -> Option<i64> {
49 match val {
50 DecodedValue::Int8(v) => Some(*v as i64),
51 DecodedValue::Int16(v) => Some(*v as i64),
52 DecodedValue::Int32(v) => Some(*v as i64),
53 DecodedValue::Int64(v) => Some(*v),
54 DecodedValue::UInt8(v) => Some(*v as i64),
55 DecodedValue::UInt16(v) => Some(*v as i64),
56 DecodedValue::UInt32(v) => Some(*v as i64),
57 DecodedValue::UInt64(v) => i64::try_from(*v).ok(),
58 DecodedValue::Boolean(v) => Some(if *v { 1 } else { 0 }),
59 DecodedValue::Float32(v) => Some(*v as i64),
60 DecodedValue::Float64(v) => Some(*v as i64),
61 _ => None,
62 }
63}
64
65pub fn decoded_to_u8(val: &DecodedValue) -> Option<u8> {
66 decoded_to_u64(val).and_then(|v| u8::try_from(v).ok())
67}
68
69pub fn decoded_to_u16(val: &DecodedValue) -> Option<u16> {
70 decoded_to_u64(val).and_then(|v| u16::try_from(v).ok())
71}
72
73pub fn decoded_to_u32(val: &DecodedValue) -> Option<u32> {
74 decoded_to_u64(val).and_then(|v| u32::try_from(v).ok())
75}
76
77pub fn decoded_to_u64(val: &DecodedValue) -> Option<u64> {
78 match val {
79 DecodedValue::Int8(v) => (*v >= 0).then_some(*v as u64),
80 DecodedValue::Int16(v) => (*v >= 0).then_some(*v as u64),
81 DecodedValue::Int32(v) => (*v >= 0).then_some(*v as u64),
82 DecodedValue::Int64(v) => (*v >= 0).then_some(*v as u64),
83 DecodedValue::UInt8(v) => Some(*v as u64),
84 DecodedValue::UInt16(v) => Some(*v as u64),
85 DecodedValue::UInt32(v) => Some(*v as u64),
86 DecodedValue::UInt64(v) => Some(*v),
87 DecodedValue::Boolean(v) => Some(if *v { 1 } else { 0 }),
88 DecodedValue::Float32(v) => (*v >= 0.0).then_some(*v as u64),
89 DecodedValue::Float64(v) => (*v >= 0.0).then_some(*v as u64),
90 _ => None,
91 }
92}
93
94pub fn decoded_to_f32(val: &DecodedValue) -> Option<f32> {
95 decoded_to_f64(val).map(|v| v as f32)
96}
97
98pub fn decoded_to_f64(val: &DecodedValue) -> Option<f64> {
99 match val {
100 DecodedValue::Float64(v) => Some(*v),
101 DecodedValue::Float32(v) => Some(*v as f64),
102 DecodedValue::Int8(v) => Some(*v as f64),
103 DecodedValue::Int16(v) => Some(*v as f64),
104 DecodedValue::Int32(v) => Some(*v as f64),
105 DecodedValue::Int64(v) => Some(*v as f64),
106 DecodedValue::UInt8(v) => Some(*v as f64),
107 DecodedValue::UInt16(v) => Some(*v as f64),
108 DecodedValue::UInt32(v) => Some(*v as f64),
109 DecodedValue::UInt64(v) => Some(*v as f64),
110 DecodedValue::Boolean(v) => Some(if *v { 1.0 } else { 0.0 }),
111 _ => None,
112 }
113}
114
115pub fn decoded_to_string(val: &DecodedValue) -> Option<String> {
116 match val {
117 DecodedValue::String(s) => Some(s.clone()),
118 _ => None,
119 }
120}
121
122pub fn decoded_to_scalar_value(val: &DecodedValue) -> ScalarValue {
123 if let Some(b) = decoded_to_bool(val) {
124 return ScalarValue::Bool(b);
125 }
126 if let Some(i) = decoded_to_i32(val) {
127 return ScalarValue::I32(i);
128 }
129 if let Some(f) = decoded_to_f64(val) {
130 return ScalarValue::F64(f);
131 }
132 if let Some(s) = decoded_to_string(val) {
133 return ScalarValue::Str(s);
134 }
135 ScalarValue::I32(0)
136}
137
138pub fn decoded_to_scalar_array(
139 val: &DecodedValue,
140 template: &ScalarArrayValue,
141) -> Option<ScalarArrayValue> {
142 let DecodedValue::Array(items) = val else {
143 return None;
144 };
145 match template {
146 ScalarArrayValue::Bool(_) => Some(ScalarArrayValue::Bool(
147 items.iter().filter_map(decoded_to_bool).collect(),
148 )),
149 ScalarArrayValue::I8(_) => Some(ScalarArrayValue::I8(
150 items.iter().filter_map(decoded_to_i8).collect(),
151 )),
152 ScalarArrayValue::I16(_) => Some(ScalarArrayValue::I16(
153 items.iter().filter_map(decoded_to_i16).collect(),
154 )),
155 ScalarArrayValue::I32(_) => Some(ScalarArrayValue::I32(
156 items.iter().filter_map(decoded_to_i32).collect(),
157 )),
158 ScalarArrayValue::I64(_) => Some(ScalarArrayValue::I64(
159 items.iter().filter_map(decoded_to_i64).collect(),
160 )),
161 ScalarArrayValue::U8(_) => Some(ScalarArrayValue::U8(
162 items.iter().filter_map(decoded_to_u8).collect(),
163 )),
164 ScalarArrayValue::U16(_) => Some(ScalarArrayValue::U16(
165 items.iter().filter_map(decoded_to_u16).collect(),
166 )),
167 ScalarArrayValue::U32(_) => Some(ScalarArrayValue::U32(
168 items.iter().filter_map(decoded_to_u32).collect(),
169 )),
170 ScalarArrayValue::U64(_) => Some(ScalarArrayValue::U64(
171 items.iter().filter_map(decoded_to_u64).collect(),
172 )),
173 ScalarArrayValue::F32(_) => Some(ScalarArrayValue::F32(
174 items.iter().filter_map(decoded_to_f32).collect(),
175 )),
176 ScalarArrayValue::F64(_) => Some(ScalarArrayValue::F64(
177 items.iter().filter_map(decoded_to_f64).collect(),
178 )),
179 ScalarArrayValue::Str(_) => Some(ScalarArrayValue::Str(
180 items.iter().filter_map(decoded_to_string).collect(),
181 )),
182 }
183}
184
185pub fn decode_nt_alarm(val: &DecodedValue) -> Option<spvirit_types::NtAlarm> {
187 let DecodedValue::Structure(fields) = val else {
188 return None;
189 };
190 let severity = fields
191 .iter()
192 .find(|(n, _)| n == "severity")
193 .and_then(|(_, v)| decoded_to_i32(v))
194 .unwrap_or(0);
195 let status = fields
196 .iter()
197 .find(|(n, _)| n == "status")
198 .and_then(|(_, v)| decoded_to_i32(v))
199 .unwrap_or(0);
200 let message = fields
201 .iter()
202 .find(|(n, _)| n == "message")
203 .and_then(|(_, v)| decoded_to_string(v))
204 .unwrap_or_default();
205 Some(spvirit_types::NtAlarm {
206 severity,
207 status,
208 message,
209 })
210}
211
212pub fn decode_nt_timestamp(val: &DecodedValue) -> Option<spvirit_types::NtTimeStamp> {
214 let DecodedValue::Structure(fields) = val else {
215 return None;
216 };
217 let seconds = fields
218 .iter()
219 .find(|(n, _)| n == "secondsPastEpoch")
220 .and_then(|(_, v)| decoded_to_i64(v))
221 .unwrap_or(0);
222 let nanos = fields
223 .iter()
224 .find(|(n, _)| n == "nanoseconds")
225 .and_then(|(_, v)| decoded_to_i32(v))
226 .unwrap_or(0);
227 let user_tag = fields
228 .iter()
229 .find(|(n, _)| n == "userTag")
230 .and_then(|(_, v)| decoded_to_i32(v))
231 .unwrap_or(0);
232 Some(spvirit_types::NtTimeStamp {
233 seconds_past_epoch: seconds,
234 nanoseconds: nanos,
235 user_tag,
236 })
237}
238
239pub fn decode_nt_display(val: &DecodedValue) -> Option<spvirit_types::NtDisplay> {
241 let DecodedValue::Structure(fields) = val else {
242 return None;
243 };
244 let limit_low = fields
245 .iter()
246 .find(|(n, _)| n == "limitLow")
247 .and_then(|(_, v)| decoded_to_f64(v))
248 .unwrap_or(0.0);
249 let limit_high = fields
250 .iter()
251 .find(|(n, _)| n == "limitHigh")
252 .and_then(|(_, v)| decoded_to_f64(v))
253 .unwrap_or(0.0);
254 let description = fields
255 .iter()
256 .find(|(n, _)| n == "description")
257 .and_then(|(_, v)| decoded_to_string(v))
258 .unwrap_or_default();
259 let units = fields
260 .iter()
261 .find(|(n, _)| n == "units")
262 .and_then(|(_, v)| decoded_to_string(v))
263 .unwrap_or_default();
264 let precision = fields
265 .iter()
266 .find(|(n, _)| n == "precision")
267 .and_then(|(_, v)| decoded_to_i32(v))
268 .unwrap_or(0);
269 Some(spvirit_types::NtDisplay {
270 limit_low,
271 limit_high,
272 description,
273 units,
274 precision,
275 })
276}