Skip to main content

kuksa_rust_sdk/
lib.rs

1/*
2 * *******************************************************************************
3 *  Copyright (c) 2025 Contributors to the Eclipse Foundation
4 *
5 *  See the NOTICE file(s) distributed with this work for additional
6 *  information regarding copyright ownership.
7 *
8 *  This program and the accompanying materials are made available under the
9 *  terms of the Apache License 2.0 which is available at
10 *  http://www.apache.org/licenses/LICENSE-2.0
11 *
12 *  SPDX-License-Identifier: Apache-2.0
13 * ******************************************************************************
14 */
15
16pub use crate::proto::kuksa::val::v1 as v1_proto;
17pub use crate::proto::kuksa::val::v2 as v2_proto;
18pub use crate::proto::sdv::databroker::v1 as sdv_proto;
19
20pub mod kuksa {
21    pub mod common;
22    pub mod val {
23        pub mod v1;
24
25        pub mod v2;
26    }
27}
28
29pub mod sdv {
30    pub mod databroker {
31        pub mod v1;
32    }
33}
34
35pub mod proto {
36    pub mod kuksa {
37        pub mod val {
38            // we need to add this, as the code generated from .proto files contain document strings that clippy does not like.
39            #[allow(clippy::doc_lazy_continuation)]
40            pub mod v1 {
41                pub const FILE_DESCRIPTOR_SET: &[u8] =
42                    tonic::include_file_descriptor_set!("kuksa.val.v1_descriptor");
43                tonic::include_proto!("kuksa.val.v1");
44
45                use datapoint::Value;
46                use std::{any::Any, fmt::Display, str::FromStr};
47
48                #[derive(Debug)]
49                pub struct ParsingError {
50                    message: String,
51                }
52
53                impl ParsingError {
54                    pub fn new<T: Into<String>>(message: T) -> Self {
55                        ParsingError {
56                            message: message.into(),
57                        }
58                    }
59                }
60
61                impl Display for ParsingError {
62                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
63                        self.message.fmt(f)
64                    }
65                }
66
67                impl std::error::Error for ParsingError {}
68
69                impl FromStr for DataType {
70                    type Err = ParsingError;
71                    fn from_str(s: &str) -> Result<Self, Self::Err> {
72                        match s.to_lowercase().as_str() {
73                            "string" => Ok(DataType::String),
74                            "string[]" => Ok(DataType::StringArray),
75                            "bool" => Ok(DataType::Boolean),
76                            "bool[]" => Ok(DataType::BooleanArray),
77                            "int8" => Ok(DataType::Int8),
78                            "int8[]" => Ok(DataType::Int8Array),
79                            "int16" => Ok(DataType::Int16),
80                            "int16[]" => Ok(DataType::Int16Array),
81                            "int32" => Ok(DataType::Int32),
82                            "int32[]" => Ok(DataType::Int32Array),
83                            "int64" => Ok(DataType::Int64),
84                            "int64[]" => Ok(DataType::Int64Array),
85                            "uint8" => Ok(DataType::Uint8),
86                            "uint8[]" => Ok(DataType::Uint8Array),
87                            "uint16" => Ok(DataType::Uint16),
88                            "uint16[]" => Ok(DataType::Uint16Array),
89                            "uint32" => Ok(DataType::Uint32),
90                            "uint32[]" => Ok(DataType::Uint32Array),
91                            "uint64" => Ok(DataType::Uint64),
92                            "uint64[]" => Ok(DataType::Uint64Array),
93                            "float" => Ok(DataType::Float),
94                            "float[]" => Ok(DataType::FloatArray),
95                            "double" => Ok(DataType::Double),
96                            "double[]" => Ok(DataType::DoubleArray),
97                            _ => Err(ParsingError::new(format!("unsupported data type '{s}'"))),
98                        }
99                    }
100                }
101
102                impl Value {
103                    pub fn new<T: Into<DataType>>(
104                        vss_type: T,
105                        value: &str,
106                    ) -> Result<Self, ParsingError> {
107                        let dt: DataType = vss_type.into();
108                        match dt {
109                            DataType::String => Ok(Value::String(value.to_string())),
110                            DataType::Boolean => value
111                                .parse::<bool>()
112                                .map(Value::Bool)
113                                .map_err(|e| ParsingError::new(e.to_string())),
114                            DataType::Int8 => value
115                                .parse::<i8>()
116                                .map(|v| Value::Int32(v as i32))
117                                .map_err(|e| ParsingError::new(e.to_string())),
118                            DataType::Int16 => value
119                                .parse::<i16>()
120                                .map(|v| Value::Int32(v as i32))
121                                .map_err(|e| ParsingError::new(e.to_string())),
122                            DataType::Int32 => value
123                                .parse::<i32>()
124                                .map(Value::Int32)
125                                .map_err(|e| ParsingError::new(e.to_string())),
126                            DataType::Int64 => value
127                                .parse::<i64>()
128                                .map(Value::Int64)
129                                .map_err(|e| ParsingError::new(e.to_string())),
130                            DataType::Uint8 => value
131                                .parse::<u8>()
132                                .map(|v| Value::Uint32(v as u32))
133                                .map_err(|e| ParsingError::new(e.to_string())),
134                            DataType::Uint16 => value
135                                .parse::<u16>()
136                                .map(|v| Value::Uint32(v as u32))
137                                .map_err(|e| ParsingError::new(e.to_string())),
138                            DataType::Uint32 => value
139                                .parse::<u32>()
140                                .map(Value::Uint32)
141                                .map_err(|e| ParsingError::new(e.to_string())),
142                            DataType::Uint64 => value
143                                .parse::<u64>()
144                                .map(Value::Uint64)
145                                .map_err(|e| ParsingError::new(e.to_string())),
146                            DataType::Float => value
147                                .parse::<f32>()
148                                .map(Value::Float)
149                                .map_err(|e| ParsingError::new(e.to_string())),
150                            DataType::Double => value
151                                .parse::<f64>()
152                                .map(Value::Double)
153                                .map_err(|e| ParsingError::new(e.to_string())),
154                            _ => Err(ParsingError::new(format!(
155                                "data type '{:?}' not supported for parsing string into typed value",
156                                dt.type_id()
157                            ))),
158                        }
159                    }
160                }
161            }
162            // we need to add this, as the code generated from .proto files contain document strings that clippy does not like.
163            #[allow(clippy::doc_lazy_continuation)]
164            pub mod v2 {
165                use value::TypedValue;
166
167                tonic::include_proto!("kuksa.val.v2");
168
169                pub const FILE_DESCRIPTOR_SET: &[u8] =
170                    tonic::include_file_descriptor_set!("kuksa.val.v2_descriptor");
171
172                /// Indicates that a [`TypedValue`] cannot be converted to the
173                /// desired type because it its value has an incompatible type.
174                #[derive(Debug)]
175                pub struct IncompatibleValueTypeError {}
176
177                impl TryFrom<TypedValue> for u32 {
178                    type Error = IncompatibleValueTypeError;
179                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
180                        Self::try_from(&value)
181                    }
182                }
183
184                impl TryFrom<&TypedValue> for u32 {
185                    type Error = IncompatibleValueTypeError;
186                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
187                        match value {
188                            TypedValue::Uint32(v) => Ok(*v),
189                            _ => Err(IncompatibleValueTypeError {}),
190                        }
191                    }
192                }
193
194                impl TryFrom<TypedValue> for Vec<u32> {
195                    type Error = IncompatibleValueTypeError;
196                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
197                        Self::try_from(&value)
198                    }
199                }
200
201                impl TryFrom<&TypedValue> for Vec<u32> {
202                    type Error = IncompatibleValueTypeError;
203                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
204                        match value {
205                            TypedValue::Uint32Array(v) => Ok(v.values.clone()),
206                            _ => Err(IncompatibleValueTypeError {}),
207                        }
208                    }
209                }
210
211                impl TryFrom<TypedValue> for u64 {
212                    type Error = IncompatibleValueTypeError;
213                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
214                        Self::try_from(&value)
215                    }
216                }
217
218                impl TryFrom<&TypedValue> for u64 {
219                    type Error = IncompatibleValueTypeError;
220                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
221                        match value {
222                            TypedValue::Uint32(v) => Ok(*v as u64),
223                            TypedValue::Uint64(v) => Ok(*v),
224                            _ => Err(IncompatibleValueTypeError {}),
225                        }
226                    }
227                }
228
229                impl TryFrom<TypedValue> for Vec<u64> {
230                    type Error = IncompatibleValueTypeError;
231                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
232                        Self::try_from(&value)
233                    }
234                }
235
236                impl TryFrom<&TypedValue> for Vec<u64> {
237                    type Error = IncompatibleValueTypeError;
238                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
239                        match value {
240                            TypedValue::Uint32Array(v) => {
241                                Ok(v.values.iter().map(|v| *v as u64).collect())
242                            }
243                            TypedValue::Uint64Array(v) => Ok(v.values.clone()),
244                            _ => Err(IncompatibleValueTypeError {}),
245                        }
246                    }
247                }
248
249                impl TryFrom<TypedValue> for i32 {
250                    type Error = IncompatibleValueTypeError;
251                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
252                        Self::try_from(&value)
253                    }
254                }
255
256                impl TryFrom<&TypedValue> for i32 {
257                    type Error = IncompatibleValueTypeError;
258                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
259                        match value {
260                            TypedValue::Uint32(v) => {
261                                i32::try_from(*v).map_err(|_e| IncompatibleValueTypeError {})
262                            }
263                            TypedValue::Int32(v) => Ok(*v),
264                            _ => Err(IncompatibleValueTypeError {}),
265                        }
266                    }
267                }
268
269                impl TryFrom<TypedValue> for Vec<i32> {
270                    type Error = IncompatibleValueTypeError;
271                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
272                        Self::try_from(&value)
273                    }
274                }
275
276                impl TryFrom<&TypedValue> for Vec<i32> {
277                    type Error = IncompatibleValueTypeError;
278                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
279                        match value {
280                            TypedValue::Uint32Array(v) => {
281                                let mut result = vec![];
282                                for u in &v.values {
283                                    result.push(
284                                        i32::try_from(*u)
285                                            .map_err(|_e| IncompatibleValueTypeError {})?,
286                                    );
287                                }
288                                Ok(result)
289                            }
290                            TypedValue::Int32Array(v) => Ok(v.values.clone()),
291                            _ => Err(IncompatibleValueTypeError {}),
292                        }
293                    }
294                }
295
296                impl TryFrom<TypedValue> for i64 {
297                    type Error = IncompatibleValueTypeError;
298                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
299                        Self::try_from(&value)
300                    }
301                }
302
303                impl TryFrom<&TypedValue> for i64 {
304                    type Error = IncompatibleValueTypeError;
305                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
306                        match value {
307                            TypedValue::Uint32(v) => Ok(*v as i64),
308                            TypedValue::Uint64(v) => {
309                                i64::try_from(*v).map_err(|_e| IncompatibleValueTypeError {})
310                            }
311                            TypedValue::Int32(v) => Ok(*v as i64),
312                            TypedValue::Int64(v) => Ok(*v),
313                            _ => Err(IncompatibleValueTypeError {}),
314                        }
315                    }
316                }
317
318                impl TryFrom<TypedValue> for Vec<i64> {
319                    type Error = IncompatibleValueTypeError;
320                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
321                        Self::try_from(&value)
322                    }
323                }
324
325                impl TryFrom<&TypedValue> for Vec<i64> {
326                    type Error = IncompatibleValueTypeError;
327                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
328                        match value {
329                            TypedValue::Uint32Array(v) => {
330                                Ok(v.values.iter().map(|v| *v as i64).collect())
331                            }
332                            TypedValue::Uint64Array(v) => {
333                                let mut result = vec![];
334                                for u in &v.values {
335                                    result.push(
336                                        i64::try_from(*u)
337                                            .map_err(|_e| IncompatibleValueTypeError {})?,
338                                    );
339                                }
340                                Ok(result)
341                            }
342                            TypedValue::Int32Array(v) => {
343                                Ok(v.values.iter().map(|v| *v as i64).collect())
344                            }
345                            TypedValue::Int64Array(v) => Ok(v.values.clone()),
346                            _ => Err(IncompatibleValueTypeError {}),
347                        }
348                    }
349                }
350
351                impl TryFrom<TypedValue> for f32 {
352                    type Error = IncompatibleValueTypeError;
353                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
354                        Self::try_from(&value)
355                    }
356                }
357
358                impl TryFrom<&TypedValue> for f32 {
359                    type Error = IncompatibleValueTypeError;
360                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
361                        match value {
362                            TypedValue::Uint32(v) => Ok(*v as f32),
363                            TypedValue::Int32(v) => Ok(*v as f32),
364                            TypedValue::Float(v) => Ok(*v),
365                            _ => Err(IncompatibleValueTypeError {}),
366                        }
367                    }
368                }
369
370                impl TryFrom<TypedValue> for Vec<f32> {
371                    type Error = IncompatibleValueTypeError;
372                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
373                        Self::try_from(&value)
374                    }
375                }
376
377                impl TryFrom<&TypedValue> for Vec<f32> {
378                    type Error = IncompatibleValueTypeError;
379                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
380                        match value {
381                            TypedValue::Uint32Array(v) => {
382                                Ok(v.values.iter().map(|v| *v as f32).collect())
383                            }
384                            TypedValue::Int32Array(v) => {
385                                Ok(v.values.iter().map(|v| *v as f32).collect())
386                            }
387                            TypedValue::FloatArray(v) => Ok(v.values.clone()),
388                            _ => Err(IncompatibleValueTypeError {}),
389                        }
390                    }
391                }
392
393                impl TryFrom<TypedValue> for f64 {
394                    type Error = IncompatibleValueTypeError;
395                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
396                        Self::try_from(&value)
397                    }
398                }
399
400                impl TryFrom<&TypedValue> for f64 {
401                    type Error = IncompatibleValueTypeError;
402                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
403                        match value {
404                            TypedValue::Uint32(v) => Ok(*v as f64),
405                            TypedValue::Uint64(v) => Ok(*v as f64),
406                            TypedValue::Int32(v) => Ok(*v as f64),
407                            TypedValue::Int64(v) => Ok(*v as f64),
408                            TypedValue::Float(v) => Ok(*v as f64),
409                            TypedValue::Double(v) => Ok(*v),
410                            _ => Err(IncompatibleValueTypeError {}),
411                        }
412                    }
413                }
414
415                impl TryFrom<TypedValue> for Vec<f64> {
416                    type Error = IncompatibleValueTypeError;
417                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
418                        Self::try_from(&value)
419                    }
420                }
421
422                impl TryFrom<&TypedValue> for Vec<f64> {
423                    type Error = IncompatibleValueTypeError;
424                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
425                        match value {
426                            TypedValue::Uint32Array(v) => {
427                                Ok(v.values.iter().map(|v| *v as f64).collect())
428                            }
429                            TypedValue::Uint64Array(v) => {
430                                Ok(v.values.iter().map(|v| *v as f64).collect())
431                            }
432                            TypedValue::Int32Array(v) => {
433                                Ok(v.values.iter().map(|v| *v as f64).collect())
434                            }
435                            TypedValue::Int64Array(v) => {
436                                Ok(v.values.iter().map(|v| *v as f64).collect())
437                            }
438                            TypedValue::FloatArray(v) => {
439                                Ok(v.values.iter().map(|v| *v as f64).collect())
440                            }
441                            TypedValue::DoubleArray(v) => Ok(v.values.clone()),
442                            _ => Err(IncompatibleValueTypeError {}),
443                        }
444                    }
445                }
446
447                impl TryFrom<TypedValue> for String {
448                    type Error = IncompatibleValueTypeError;
449                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
450                        Self::try_from(&value)
451                    }
452                }
453
454                impl TryFrom<&TypedValue> for String {
455                    type Error = IncompatibleValueTypeError;
456                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
457                        match value {
458                            TypedValue::String(v) => Ok(v.to_string()),
459                            _ => Err(IncompatibleValueTypeError {}),
460                        }
461                    }
462                }
463
464                impl TryFrom<TypedValue> for Vec<String> {
465                    type Error = IncompatibleValueTypeError;
466                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
467                        Self::try_from(&value)
468                    }
469                }
470
471                impl TryFrom<&TypedValue> for Vec<String> {
472                    type Error = IncompatibleValueTypeError;
473                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
474                        match value {
475                            TypedValue::StringArray(v) => Ok(v.values.clone()),
476                            _ => Err(IncompatibleValueTypeError {}),
477                        }
478                    }
479                }
480
481                impl TryFrom<TypedValue> for bool {
482                    type Error = IncompatibleValueTypeError;
483                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
484                        Self::try_from(&value)
485                    }
486                }
487
488                impl TryFrom<&TypedValue> for bool {
489                    type Error = IncompatibleValueTypeError;
490                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
491                        match value {
492                            TypedValue::Bool(v) => Ok(*v),
493                            _ => Err(IncompatibleValueTypeError {}),
494                        }
495                    }
496                }
497
498                impl TryFrom<TypedValue> for Vec<bool> {
499                    type Error = IncompatibleValueTypeError;
500                    fn try_from(value: TypedValue) -> Result<Self, Self::Error> {
501                        Self::try_from(&value)
502                    }
503                }
504
505                impl TryFrom<&TypedValue> for Vec<bool> {
506                    type Error = IncompatibleValueTypeError;
507                    fn try_from(value: &TypedValue) -> Result<Self, Self::Error> {
508                        match value {
509                            TypedValue::BoolArray(v) => Ok(v.values.clone()),
510                            _ => Err(IncompatibleValueTypeError {}),
511                        }
512                    }
513                }
514            }
515        }
516    }
517    pub mod sdv {
518        pub mod databroker {
519            // we need to add this, as the code generated from .proto files contain document strings that clippy does not like.
520            #[allow(clippy::doc_lazy_continuation)]
521            pub mod v1 {
522                pub const FILE_DESCRIPTOR_SET: &[u8] =
523                    tonic::include_file_descriptor_set!("sdv.databroker.v1_descriptor");
524                tonic::include_proto!("sdv.databroker.v1");
525            }
526        }
527    }
528}
529
530#[cfg(test)]
531mod tests {
532    use super::*;
533    use crate::v2_proto::value::TypedValue;
534    use test_case::test_case;
535
536    #[test_case(
537        TypedValue::String("one".to_string()),
538        "one".to_string();
539        "for String")]
540    #[test_case(
541        TypedValue::StringArray(proto::kuksa::val::v2::StringArray { values: vec!["one".to_string(), "two".to_string()] }),
542        vec!["one".to_string(), "two".to_string()];
543        "for StringArray")]
544    #[test_case(
545        TypedValue::Bool(true),
546        true;
547        "for Bool")]
548    #[test_case(
549        TypedValue::BoolArray(proto::kuksa::val::v2::BoolArray { values: vec![true, false] }),
550        vec![true, false];
551        "for BoolArray")]
552    #[test_case(
553        TypedValue::Uint32(0x01234567_u32),
554        0x01234567_u32;
555        "for UInt32")]
556    #[test_case(
557        TypedValue::Uint32Array(proto::kuksa::val::v2::Uint32Array { values: vec![0x01234567_u32, 0x89abcdef_u32] }),
558        vec![0x01234567_u32, 0x89abcdef_u32];
559        "for UInt32Array")]
560    #[test_case(
561        TypedValue::Int32(0x01234567_i32),
562        0x01234567_i32;
563        "for Int32")]
564    #[test_case(
565        TypedValue::Int32Array(proto::kuksa::val::v2::Int32Array { values: vec![0x01234567_i32, 0x89abcdef_u32 as i32] }),
566        vec![0x01234567_i32, 0x89abcdef_u32 as i32];
567        "for Int32Array")]
568    #[test_case(
569        TypedValue::Uint32(0x01234567_u32),
570        0x01234567_u32 as i32;
571        "for UInt32 as Int32")]
572    #[test_case(
573        TypedValue::Uint64(0x0123456789abcdef_u64),
574        0x0123456789abcdef_u64;
575        "for UInt64")]
576    #[test_case(
577        TypedValue::Uint64Array(proto::kuksa::val::v2::Uint64Array { values: vec![0x0123456789abcdef_u64, 0x0123456789abcdef_u64] }),
578        vec![0x0123456789abcdef_u64, 0x0123456789abcdef_u64];
579        "for UInt64Array")]
580    #[test_case(
581        TypedValue::Uint32(0x01234567_u32),
582        0x01234567_u32 as u64;
583        "for UInt32 as UInt64")]
584    #[test_case(
585        TypedValue::Uint32Array(proto::kuksa::val::v2::Uint32Array { values: vec![0x01234567_u32, 0x89abcdef_u32] }),
586        vec![0x01234567_u32 as u64, 0x89abcdef_u32 as u64];
587        "for UInt32Array as UInt64Array")]
588    #[test_case(
589        TypedValue::Int64(0x0123456789abcdef_i64),
590        0x0123456789abcdef_i64;
591        "for Int64")]
592    #[test_case(
593        TypedValue::Int64Array(proto::kuksa::val::v2::Int64Array { values: vec![0x0123456789abcdef_i64, 0xfedcba9876543210_u64 as i64] }),
594        vec![0x0123456789abcdef_i64, 0xfedcba9876543210_u64 as i64];
595        "for Int64Array")]
596    #[test_case(
597        TypedValue::Uint32(0x01234567_u32),
598        0x01234567_u32 as i64;
599        "for UInt32 as Int64")]
600    #[test_case(
601        TypedValue::Uint32Array(proto::kuksa::val::v2::Uint32Array { values: vec![0x01234567_u32, 0x89abcdef_u32] }),
602        vec![0x01234567_u32 as i64, 0x89abcdef_u32 as i64];
603        "for UInt32Array as Int64Array")]
604    #[test_case(
605        TypedValue::Int32(0x01234567_i32),
606        0x01234567_i32 as i64;
607        "for Int32 as Int64")]
608    #[test_case(
609        TypedValue::Int32Array(proto::kuksa::val::v2::Int32Array { values: vec![0x01234567_i32, 0x89abcdef_u32 as i32] }),
610        vec![0x01234567_i32 as i64, (0x89abcdef_u32 as i32) as i64];
611        "for Int32Array as Int64Array")]
612    #[test_case(
613        TypedValue::Float(34.345),
614        34.345_f32;
615        "for Float")]
616    #[test_case(
617        TypedValue::FloatArray(proto::kuksa::val::v2::FloatArray { values: vec![34.345, -34.345] }),
618        vec![34.345_f32, -34.345_f32];
619        "for FloatArray")]
620    #[test_case(
621        TypedValue::Uint32(0x01234567_u32),
622        0x01234567_u32 as f32;
623        "for UInt32 as Float")]
624    #[test_case(
625        TypedValue::Uint32Array(proto::kuksa::val::v2::Uint32Array { values: vec![0x01234567_u32, 0x89abcdef_u32] }),
626        vec![0x01234567_u32 as f32, 0x89abcdef_u32 as f32];
627        "for UInt32Array as Float32Array")]
628    #[test_case(
629        TypedValue::Int32(0x01234567_i32),
630        0x01234567_i32 as f32;
631        "for Int32 as Float")]
632    #[test_case(
633        TypedValue::Int32Array(proto::kuksa::val::v2::Int32Array { values: vec![0x01234567_i32, 0x89abcdef_u32 as i32] }),
634        vec![0x01234567_i32 as f32, (0x89abcdef_u32 as i32) as f32];
635        "for Int32Array as FloatArray")]
636    #[test_case(
637        TypedValue::Double(34.345),
638        34.345_f64;
639        "for Double")]
640    #[test_case(
641        TypedValue::DoubleArray(proto::kuksa::val::v2::DoubleArray { values: vec![34.345, -34.345] }),
642        vec![34.345_f64, -34.345_f64];
643        "for DoubleArray")]
644    #[test_case(
645        TypedValue::Float(34.345),
646        34.345_f32 as f64;
647        "for Float as Double")]
648    #[test_case(
649        TypedValue::FloatArray(proto::kuksa::val::v2::FloatArray { values: vec![34.345, -34.345] }),
650        vec![34.345_f32 as f64, -34.345_f32 as f64];
651        "for FloatArray as DoubleArray")]
652    #[test_case(
653        TypedValue::Uint32(0x89abcdef_u32),
654        0x89abcdef_u32 as f64;
655        "for UInt32 as Double")]
656    #[test_case(
657        TypedValue::Uint32Array(proto::kuksa::val::v2::Uint32Array { values: vec![0x01234567_u32, 0x89abcdef_u32] }),
658        vec![0x01234567_u32 as f64, 0x89abcdef_u32 as f64];
659        "for UInt32Array as DoubleArray")]
660    #[test_case(
661        TypedValue::Uint64(0xfedcba9876543210_u64),
662        0xfedcba9876543210_u64 as f64;
663        "for UInt64 as Double")]
664    #[test_case(
665        TypedValue::Uint64Array(proto::kuksa::val::v2::Uint64Array { values: vec![0x0123456789abcdef_u64, 0xfedcba9876543210_u64] }),
666        vec![0x0123456789abcdef_u64 as f64, 0xfedcba9876543210_u64 as f64];
667        "for UInt64Array as DoubleArray")]
668    #[test_case(
669        TypedValue::Int32(0x01234567_i32),
670        0x01234567_i32 as f64;
671        "for Int32 as Double")]
672    #[test_case(
673        TypedValue::Int32Array(proto::kuksa::val::v2::Int32Array { values: vec![0x01234567_i32, 0x89abcdef_u32 as i32] }),
674        vec![0x01234567_i32 as f64, (0x89abcdef_u32 as i32) as f64];
675        "for Int32Array as DoubleArray")]
676    #[test_case(
677        TypedValue::Int64(0x0123456789abcdef_i64),
678        0x0123456789abcdef_i64 as f64;
679        "for Int64 as Double")]
680    #[test_case(
681        TypedValue::Int64Array(proto::kuksa::val::v2::Int64Array { values: vec![0x0123456789abcdef_i64, 0xfedcba9876543210_u64 as i64] }),
682        vec![0x0123456789abcdef_i64, 0xfedcba9876543210_u64 as i64];
683        "for Int64Array as DoubleArray")]
684    fn test_try_from_typedvalue<T>(data: TypedValue, expected_value: T)
685    where
686        T: Sized
687            + std::convert::TryFrom<proto::kuksa::val::v2::value::TypedValue>
688            + std::cmp::PartialEq,
689    {
690        assert!(T::try_from(data).is_ok_and(|v| v.eq(&expected_value)));
691    }
692
693    #[test]
694    fn test_try_from_uint32_fails() {
695        assert!(i32::try_from(TypedValue::Uint32(0x90000000_u32)).is_err());
696    }
697
698    #[test]
699    fn test_try_from_uint32array_fails() {
700        let v = TypedValue::Uint32Array(proto::kuksa::val::v2::Uint32Array {
701            values: vec![0x90000000_u32],
702        });
703        assert!(Vec::<i32>::try_from(v).is_err());
704    }
705
706    #[test]
707    fn test_try_from_uint64_fails() {
708        assert!(i64::try_from(TypedValue::Uint64(0x9000000000000000_u64)).is_err());
709    }
710
711    #[test]
712    fn test_try_from_uint64array_fails() {
713        let v = TypedValue::Uint64Array(proto::kuksa::val::v2::Uint64Array {
714            values: vec![0x9000000000000000_u64],
715        });
716        assert!(Vec::<i64>::try_from(v).is_err());
717    }
718}