msr_core/value/
mod.rs

1use std::{fmt, time::Duration};
2
3// TODO: Make `scalar` module public instead of renaming and re-exporting all types?
4mod scalar;
5pub use self::scalar::{Type as ScalarType, Value as ScalarValue};
6
7pub trait ToValueType {
8    fn to_value_type(&self) -> ValueType;
9}
10
11/// Enumeration of value types
12#[derive(Debug, Copy, Clone, PartialEq, Eq)]
13pub enum ValueType {
14    /// Scalar type
15    Scalar(ScalarType),
16
17    /// Time duration, e.g. a timeout
18    Duration,
19
20    /// Text data
21    String,
22
23    /// Binary data
24    Bytes,
25}
26
27// TODO: Use short identifiers?
28const TYPE_STR_DURATION: &str = "duration";
29const TYPE_STR_STRING: &str = "string";
30const TYPE_STR_BYTES: &str = "bytes";
31
32impl ValueType {
33    #[must_use]
34    pub const fn to_scalar(self) -> Option<ScalarType> {
35        match self {
36            Self::Scalar(s) => Some(s),
37            _ => None,
38        }
39    }
40
41    #[must_use]
42    pub const fn is_scalar(self) -> bool {
43        self.to_scalar().is_some()
44    }
45
46    #[must_use]
47    pub const fn from_scalar(scalar: ScalarType) -> Self {
48        Self::Scalar(scalar)
49    }
50
51    const fn as_str(self) -> &'static str {
52        match self {
53            Self::Scalar(s) => s.as_str(),
54            Self::Duration => TYPE_STR_DURATION,
55            Self::String => TYPE_STR_STRING,
56            Self::Bytes => TYPE_STR_BYTES,
57        }
58    }
59
60    #[must_use]
61    pub fn try_from_str(s: &str) -> Option<Self> {
62        ScalarType::try_from_str(s).map(Into::into).or(match s {
63            TYPE_STR_DURATION => Some(Self::Duration),
64            TYPE_STR_STRING => Some(Self::String),
65            TYPE_STR_BYTES => Some(Self::Bytes),
66            _ => None,
67        })
68    }
69}
70
71impl From<ScalarType> for ValueType {
72    fn from(from: ScalarType) -> Self {
73        Self::from_scalar(from)
74    }
75}
76
77impl fmt::Display for ValueType {
78    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
79        f.write_str(self.as_str())
80    }
81}
82
83/// A value representation within a MSR system.
84///
85/// TODO: Split into a separate type for simple, copyable values and
86/// an enclosing type that includes the complex, non-real-time-safe
87/// values?
88#[derive(Debug, Clone, PartialEq)]
89pub enum Value {
90    /// Scalar value (real-time safe)
91    ///
92    /// This variant can safely be used in real-time contexts.
93    Scalar(ScalarValue),
94
95    /// Duration, e.g. a timeout
96    ///
97    /// This variant can safely be used in real-time contexts.
98    Duration(Duration),
99
100    /// Variable-size text data
101    ///
102    /// This variant must not be used in real-time contexts.
103    String(String),
104
105    /// Variable-size binary data
106    ///
107    /// This variant must not be used in real-time contexts.
108    Bytes(Vec<u8>),
109}
110
111impl From<Duration> for Value {
112    fn from(from: Duration) -> Value {
113        Self::Duration(from)
114    }
115}
116
117impl From<String> for Value {
118    fn from(from: String) -> Value {
119        Self::String(from)
120    }
121}
122
123impl From<Vec<u8>> for Value {
124    fn from(from: Vec<u8>) -> Value {
125        Self::Bytes(from)
126    }
127}
128
129impl Value {
130    #[must_use]
131    pub const fn to_type(&self) -> ValueType {
132        match self {
133            Self::Scalar(value) => ValueType::Scalar(value.to_type()),
134            Self::Duration(_) => ValueType::Duration,
135            Self::String(_) => ValueType::String,
136            Self::Bytes(_) => ValueType::Bytes,
137        }
138    }
139
140    #[must_use]
141    pub const fn to_scalar(&self) -> Option<ScalarValue> {
142        match self {
143            Self::Scalar(scalar) => Some(*scalar),
144            _ => None,
145        }
146    }
147
148    #[must_use]
149    pub const fn from_scalar(scalar: ScalarValue) -> Self {
150        Self::Scalar(scalar)
151    }
152
153    pub fn to_i32(&self) -> Option<i32> {
154        self.to_scalar().and_then(ScalarValue::to_i32)
155    }
156
157    pub fn to_u32(&self) -> Option<u32> {
158        self.to_scalar().and_then(ScalarValue::to_u32)
159    }
160
161    pub fn to_i64(&self) -> Option<i64> {
162        self.to_scalar().and_then(ScalarValue::to_i64)
163    }
164
165    pub fn to_u64(&self) -> Option<u64> {
166        self.to_scalar().and_then(ScalarValue::to_u64)
167    }
168
169    pub fn to_f32(&self) -> Option<f32> {
170        self.to_scalar().and_then(ScalarValue::to_f32)
171    }
172
173    pub fn to_f64(&self) -> Option<f64> {
174        self.to_scalar().and_then(ScalarValue::to_f64)
175    }
176}
177
178impl ToValueType for Value {
179    fn to_value_type(&self) -> ValueType {
180        self.to_type()
181    }
182}
183
184impl<S> From<S> for Value
185where
186    S: Into<ScalarValue>,
187{
188    fn from(from: S) -> Self {
189        Value::Scalar(from.into())
190    }
191}