1use core::{
2 str::FromStr,
3 convert::TryFrom,
4 fmt::{Display, self, Formatter},
5};
6
7#[derive(Debug, Copy, Clone, PartialEq, PartialOrd)]
10#[non_exhaustive]
11pub enum Value {
12 Byte(u8),
13 Short(i16),
14 Integer(i32),
15 Float(f32),
16 SignedByte(i8),
17}
18
19impl Value {
20 pub const fn buffer() -> [u8; core::mem::size_of::<Value>()] {
22 [0; core::mem::size_of::<Value>()]
23 }
24
25 pub fn from_le_bytes(ty: Type, bytes: &[u8]) -> Option<Self> {
26 match ty {
27 Type::Byte => bytes.get(0).copied().map(Value::Byte),
28 Type::SignedByte => {
29 if let [byte, ..] = bytes {
30 Some(Value::SignedByte(i8::from_le_bytes([*byte])))
31 } else {
32 None
33 }
34 },
35 Type::Short => {
36 const LEN: usize = core::mem::size_of::<i16>();
37
38 bytes.get(..LEN).map(|bytes| {
39 let mut buffer = [0; LEN];
40 buffer.copy_from_slice(bytes);
41 Value::Short(i16::from_le_bytes(buffer))
42 })
43 },
44 Type::Integer => {
45 const LEN: usize = core::mem::size_of::<i32>();
46
47 bytes.get(..LEN).map(|bytes| {
48 let mut buffer = [0; LEN];
49 buffer.copy_from_slice(bytes);
50 Value::Integer(i32::from_le_bytes(buffer))
51 })
52 },
53 Type::Float => {
54 const LEN: usize = core::mem::size_of::<f32>();
55
56 bytes.get(..LEN).map(|bytes| {
57 let mut buffer = [0; LEN];
58 buffer.copy_from_slice(bytes);
59 Value::Float(f32::from_le_bytes(buffer))
60 })
61 },
62 }
63 }
64
65 pub fn to_le_bytes(self, buffer: &mut [u8]) -> usize {
72 match self {
73 Value::Byte(b) => {
74 buffer[0] = b;
75 1
76 },
77 Value::SignedByte(b) => {
78 buffer[..1].copy_from_slice(&b.to_le_bytes());
79 1
80 },
81 Value::Short(short) => {
82 let bytes = short.to_le_bytes();
83 buffer[..bytes.len()].copy_from_slice(&bytes);
84 bytes.len()
85 },
86 Value::Integer(int) => {
87 let bytes = int.to_le_bytes();
88 buffer[..bytes.len()].copy_from_slice(&bytes);
89 bytes.len()
90 },
91 Value::Float(float) => {
92 let bytes = float.to_le_bytes();
93 buffer[..bytes.len()].copy_from_slice(&bytes);
94 bytes.len()
95 },
96 }
97 }
98
99 pub fn ty(&self) -> Type {
100 match self {
101 Value::Byte(_) => Type::Byte,
102 Value::SignedByte(_) => Type::SignedByte,
103 Value::Short(_) => Type::Short,
104 Value::Integer(_) => Type::Integer,
105 Value::Float(_) => Type::Float,
106 }
107 }
108}
109
110impl Display for Value {
111 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
112 match self {
113 Value::Byte(b) => write!(f, "{}_u8", b),
114 Value::SignedByte(b) => write!(f, "{}_i8", b),
115 Value::Short(s) => write!(f, "{}_i16", s),
116 Value::Integer(i) => write!(f, "{}_i32", i),
117 Value::Float(float) => write!(f, "{:.1}", float),
118 }
119 }
120}
121
122impl FromStr for Value {
123 type Err = core::num::ParseFloatError;
124
125 fn from_str(s: &str) -> Result<Self, Self::Err> {
126 if let Ok(integer) = s.parse() {
127 Ok(Value::Integer(integer))
128 } else {
129 s.parse().map(Value::Float)
130 }
131 }
132}
133
134#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
135#[repr(u32)]
136#[non_exhaustive]
137pub enum Type {
138 Integer = 1,
140 Float = 2,
142 Byte = 5,
144 Short = 6,
146 SignedByte = 7,
157}
158
159impl From<Type> for u32 {
160 fn from(t: Type) -> Self { t as u32 }
161}
162
163impl TryFrom<u32> for Type {
164 type Error = ();
165
166 fn try_from(value: u32) -> Result<Self, Self::Error> {
167 match value {
168 1 => Ok(Type::Integer),
169 2 => Ok(Type::Float),
170 5 => Ok(Type::Byte),
171 6 => Ok(Type::Short),
172 _ => Err(()),
173 }
174 }
175}
176
177pub trait AsType
180where
181 Self: Into<Value>,
182 Self: TryFrom<Value>,
183{
184 const TYPE: Type;
186}
187
188macro_rules! impl_as_type {
189 ($($type:ty => $variant:ident),* $(,)?) => {
190 $(
191 impl AsType for $type {
192 const TYPE: Type = Type::$variant;
193 }
194
195 impl From<$type> for Value {
196 fn from(other: $type) -> Value {
197 Value::$variant(other)
198 }
199 }
200
201 impl TryFrom<Value> for $type {
202 type Error = InvalidConversionError;
203
204 fn try_from(value: Value) -> Result<Self, Self::Error> {
205 match value {
206 Value::$variant(v) => Ok(v),
207 _ => Err(InvalidConversionError {
208 value,
209 target_type: Type::$variant,
210 }),
211 }
212 }
213 }
214 )*
215 }
216}
217
218impl_as_type!(u8 => Byte, i16 => Short, i32 => Integer, f32 => Float, i8 => SignedByte);
219
220#[derive(Debug, Copy, Clone, PartialEq)]
221pub struct InvalidConversionError {
222 pub value: Value,
223 pub target_type: Type,
224}
225
226impl Display for InvalidConversionError {
227 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
228 write!(
229 f,
230 "Unable to convert {} ({:?}) to a {:?}",
231 self.value,
232 self.value.ty(),
233 self.target_type
234 )
235 }
236}
237
238#[cfg(feature = "std")]
239impl std::error::Error for InvalidConversionError {}