crazyflie_lib/
value.rs

1use half::f16;
2use serde::{Serialize, Deserialize};
3use std::convert::{TryFrom, TryInto};
4
5/// # Typed data value
6///
7/// This enum supports all the data types that can be exchanged with the Crazyflie
8/// using the [log](crate::subsystems::log) and [param](crate::subsystems::param) subsystems.
9///
10/// A function allows to convert a `[u8]` to a [Value] and the [Into<Vec<U8>>]
11/// trait is implemented to convert a [Value] into a vector of bytes.
12///
13/// The [TryFrom] trait is implemented for all matching rust primitive type. There
14/// is only direct conversion implemented. For example the following is OK:
15/// ```
16/// # use std::convert::TryInto;
17/// # use crazyflie_lib::Value;
18/// let v:u32 = Value::U32(42).try_into().unwrap();
19/// ```
20///
21/// However the following **will panic**:
22/// ``` should_panic
23/// # use std::convert::TryInto;
24/// # use crazyflie_lib::Value;
25/// let v:u32 = Value::U8(42).try_into().unwrap();
26/// ```
27#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
28pub enum Value {
29    /// [u8] value
30    U8(u8),
31    /// [u16] value
32    U16(u16),
33    /// [u32] value
34    U32(u32),
35    /// [u64] value
36    U64(u64),
37    /// [i8] value
38    I8(i8),
39    /// [i16] value
40    I16(i16),
41    /// [i32] value
42    I32(i32),
43    /// [i64] value
44    I64(i64),
45    /// [f16] value
46    F16(f16),
47    /// [f32] value
48    F32(f32),
49    /// [f64] value
50    F64(f64),
51}
52
53/// # Value type
54///
55/// This enum contains all the possible type of a [Value]
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
57pub enum ValueType {
58    /// Type of a [u8] value
59    U8,
60    /// Type of a [u16] value
61    U16,
62    /// Type of a [u32] value
63    U32,
64    /// Type of a [u64] value
65    U64,
66    /// Type of a [i8] value
67    I8,
68    /// Type of a [i16] value
69    I16,
70    /// Type of a [i32] value
71    I32,
72    /// Type of a [i64] value
73    I64,
74    /// Type of a [f16] value
75    F16,
76    /// Type of a [f32] value
77    F32,
78    /// Type of a [f64] value
79    F64,
80}
81
82impl ValueType {
83    /// Return the byte length of a value according to its type
84    pub fn byte_length(&self) -> usize {
85        match self {
86            ValueType::U8 => 1,
87            ValueType::U16 => 2,
88            ValueType::U32 => 4,
89            ValueType::U64 => 8,
90            ValueType::I8 => 1,
91            ValueType::I16 => 2,
92            ValueType::I32 => 4,
93            ValueType::I64 => 8,
94            ValueType::F16 => 2,
95            ValueType::F32 => 4,
96            ValueType::F64 => 8,
97        }
98    }
99}
100
101impl From<Value> for ValueType {
102    fn from(value: Value) -> Self {
103        match value {
104            Value::U8(_) => ValueType::U8,
105            Value::U16(_) => ValueType::U16,
106            Value::U32(_) => ValueType::U32,
107            Value::U64(_) => ValueType::U64,
108            Value::I8(_) => ValueType::I8,
109            Value::I16(_) => ValueType::I16,
110            Value::I32(_) => ValueType::I32,
111            Value::I64(_) => ValueType::I64,
112            Value::F16(_) => ValueType::F16,
113            Value::F32(_) => ValueType::F32,
114            Value::F64(_) => ValueType::F64,
115        }
116    }
117}
118
119// Conversion from and to matching primitive types
120
121macro_rules! primitive_impl {
122    ($ty:ident, $name:ident) => {
123        impl From<$ty> for Value {
124            fn from(v: $ty) -> Self {
125                Value::$name(v)
126            }
127        }
128
129        impl TryFrom<Value> for $ty {
130            type Error = crate::Error;
131
132            fn try_from(value: Value) -> Result<$ty, Self::Error> {
133                match value {
134                    Value::$name(v) => Ok(v),
135                    _ => Err(Self::Error::ConversionError(format!(
136                        "Cannot convert {:?} to {}",
137                        value,
138                        stringify!($ty)
139                    ))),
140                }
141            }
142        }
143    };
144}
145
146primitive_impl!(u8, U8);
147primitive_impl!(u16, U16);
148primitive_impl!(u32, U32);
149primitive_impl!(u64, U64);
150primitive_impl!(i8, I8);
151primitive_impl!(i16, I16);
152primitive_impl!(i32, I32);
153primitive_impl!(i64, I64);
154primitive_impl!(f16, F16);
155primitive_impl!(f32, F32);
156primitive_impl!(f64, F64);
157
158// Conversion from and to u8 slice (little endian serde)
159impl Value {
160    /// Convert a `&[u8]` slice to a [Value]. The length of the slice must match
161    /// the length of the value type, otherwise an error will be returned.
162    pub fn from_le_bytes(bytes: &[u8], value_type: ValueType) -> Result<Value, crate::Error> {
163        match value_type {
164            ValueType::U8 => Ok(Value::U8(u8::from_le_bytes(bytes.try_into()?))),
165            ValueType::U16 => Ok(Value::U16(u16::from_le_bytes(bytes.try_into()?))),
166            ValueType::U32 => Ok(Value::U32(u32::from_le_bytes(bytes.try_into()?))),
167            ValueType::U64 => Ok(Value::U64(u64::from_le_bytes(bytes.try_into()?))),
168            ValueType::I8 => Ok(Value::I8(i8::from_le_bytes(bytes.try_into()?))),
169            ValueType::I16 => Ok(Value::I16(i16::from_le_bytes(bytes.try_into()?))),
170            ValueType::I32 => Ok(Value::I32(i32::from_le_bytes(bytes.try_into()?))),
171            ValueType::I64 => Ok(Value::I64(i64::from_le_bytes(bytes.try_into()?))),
172            ValueType::F16 => Ok(Value::F16(f16::from_le_bytes(bytes.try_into()?))),
173            ValueType::F32 => Ok(Value::F32(f32::from_le_bytes(bytes.try_into()?))),
174            ValueType::F64 => Ok(Value::F64(f64::from_le_bytes(bytes.try_into()?))),
175        }
176    }
177
178    /// Convert a [Value] to a [f64].
179    ///
180    /// This conversion is lossless in most case but can be lossy if the value
181    /// is a u64: a f64 cannot accurately store large values of a u64.
182    pub fn to_f64_lossy(&self) -> f64 {
183        match *self {
184            Value::U8(v) => v as f64,
185            Value::U16(v) => v as f64,
186            Value::U32(v) => v as f64,
187            Value::U64(v) => v as f64,
188            Value::I8(v) => v as f64,
189            Value::I16(v) => v as f64,
190            Value::I32(v) => v as f64,
191            Value::I64(v) => v as f64,
192            Value::F16(v) => v.to_f64(),
193            Value::F32(v) => v as f64,
194            Value::F64(v) => v as f64,
195        }
196    }
197
198    /// Make a [Value] from a [f64] and a [ValueType]
199    ///
200    /// This function allows to construct any type of value from a f64.
201    ///
202    /// The conversion has possibility to be lossy in a couple of cases:
203    ///  - When making an integer, the value is truncated to the number of bit of the parameter
204    ///    - Example: Setting `257` to a `u8` variable will set it to the value `1`
205    ///  - Similarly floating point precision will be truncated to the parameter precision. Rounding is undefined.
206    ///  - Making a floating point outside the range of the parameter is undefined.
207    ///  - It is not possible to represent accurately a `u64` parameter in a `f64`.
208    pub fn from_f64_lossy(value_type: ValueType, value: f64) -> Value {
209        match value_type {
210            ValueType::U8 => Value::U8((value as u64) as u8),
211            ValueType::U16 => Value::U16((value as u64) as u16),
212            ValueType::U32 => Value::U32((value as u64) as u32),
213            ValueType::U64 => Value::U64((value as u64) as u64),
214            ValueType::I8 => Value::I8((value as i64) as i8),
215            ValueType::I16 => Value::I16((value as i64) as i16),
216            ValueType::I32 => Value::I32((value as i64) as i32),
217            ValueType::I64 => Value::I64((value as i64) as i64),
218            ValueType::F16 => Value::F16(f16::from_f64(value)),
219            ValueType::F32 => Value::F32(value as f32),
220            ValueType::F64 => Value::F64(value),
221        }
222    }
223}
224
225impl From<Value> for Vec<u8> {
226    fn from(value: Value) -> Self {
227        match value {
228            Value::U8(v) => v.to_le_bytes().into(),
229            Value::U16(v) => v.to_le_bytes().into(),
230            Value::U32(v) => v.to_le_bytes().into(),
231            Value::U64(v) => v.to_le_bytes().into(),
232            Value::I8(v) => v.to_le_bytes().into(),
233            Value::I16(v) => v.to_le_bytes().into(),
234            Value::I32(v) => v.to_le_bytes().into(),
235            Value::I64(v) => v.to_le_bytes().into(),
236            Value::F16(v) => v.to_le_bytes().into(),
237            Value::F32(v) => v.to_le_bytes().into(),
238            Value::F64(v) => v.to_le_bytes().into(),
239        }
240    }
241}