frc_value/
lib.rs

1use std::{
2    collections::HashMap,
3    fmt::Display,
4    hash::{Hash, Hasher},
5};
6
7use bytes::Bytes;
8use protobuf::descriptor::FileDescriptorProto;
9use serde::{Deserialize, Serialize};
10
11#[cfg(test)]
12mod test;
13mod trait_impls;
14mod traits;
15mod error;
16
17pub use traits::IntoFrcValue;
18pub use error::FrcValueError;
19
20///Measured in microseconds <p>
21/// depending on source can be from unix epoch or some arbitrary start time
22pub type FrcTimestamp = u64;
23
24pub fn now() -> FrcTimestamp {
25    let now = std::time::SystemTime::now();
26    let since_epoch = now.duration_since(std::time::UNIX_EPOCH).unwrap();
27    since_epoch.as_micros() as FrcTimestamp
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub enum FrcType {
32    Void,
33    Boolean,
34    Int,
35    Double,
36    Float,
37    String,
38    BoolArray,
39    IntArray,
40    FloatArray,
41    DoubleArray,
42    StringArray,
43    Raw,
44    Struct,
45    Protobuf
46}
47impl Display for FrcType {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        match self {
50            FrcType::Void => write!(f, "Void"),
51            FrcType::Boolean => write!(f, "Boolean"),
52            FrcType::Int => write!(f, "Int"),
53            FrcType::Double => write!(f, "Double"),
54            FrcType::Float => write!(f, "Float"),
55            FrcType::String => write!(f, "String"),
56            FrcType::BoolArray => write!(f, "BoolArray"),
57            FrcType::IntArray => write!(f, "IntArray"),
58            FrcType::FloatArray => write!(f, "FloatArray"),
59            FrcType::DoubleArray => write!(f, "DoubleArray"),
60            FrcType::StringArray => write!(f, "StringArray"),
61            FrcType::Raw => write!(f, "Raw"),
62            FrcType::Struct => write!(f, "Struct"),
63            FrcType::Protobuf => write!(f, "Protobuf"),
64        }
65    }
66}
67
68impl Serialize for FrcType {
69    fn serialize<S>(
70        &self,
71        serializer: S,
72    ) -> Result<<S as serde::Serializer>::Ok, <S as serde::Serializer>::Error>
73    where
74        S: serde::Serializer,
75    {
76        serializer.serialize_str(&self.to_string().to_lowercase().replace("array", "[]"))
77    }
78}
79
80impl<'a> Deserialize<'a> for FrcType {
81    fn deserialize<D>(deserializer: D) -> Result<Self, <D as serde::Deserializer<'a>>::Error>
82    where
83        D: serde::Deserializer<'a>,
84    {
85        let s = String::deserialize(deserializer)?;
86        match s.as_str() {
87            "boolean" => Ok(FrcType::Boolean),
88            "int" => Ok(FrcType::Int),
89            "double" => Ok(FrcType::Double),
90            "float" => Ok(FrcType::Float),
91            "string" => Ok(FrcType::String),
92            "json" => Ok(FrcType::String),
93            "bool[]" => Ok(FrcType::BoolArray),
94            "int[]" => Ok(FrcType::IntArray),
95            "float[]" => Ok(FrcType::FloatArray),
96            "double[]" => Ok(FrcType::DoubleArray),
97            "string[]" => Ok(FrcType::StringArray),
98            "raw" => Ok(FrcType::Raw),
99            "rpc" => Ok(FrcType::Raw),
100            "msgpack" => Ok(FrcType::Raw),
101            "protobuf" => Ok(FrcType::Protobuf),
102            "struct" => Ok(FrcType::Struct),
103            _ => Err(serde::de::Error::custom(format!("Invalid FrcType: {}", s))),
104        }
105    }
106}
107
108/// A stardized value type for FRC data piping
109/// 
110/// This enum is used to represent all possible values that can be sent over the FRC data piping system
111/// including
112/// - Void
113/// - Boolean
114/// - Int(i64)
115/// - Double
116/// - Float
117/// - String
118/// - BoolArray
119/// - IntArray
120/// - FloatArray
121/// - DoubleArray
122/// - StringArray
123/// - Raw(Bytes)
124/// - Struct
125/// - Protobuf
126/// 
127/// Struct and Protobuf are special types that carry metadata to allow them to be decoded into their inner types
128/// 
129/// Bytes are Boxed to keep the size of the enum small
130#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
131#[serde(untagged)]
132pub enum FrcValue {
133    Void,
134    Boolean(bool),
135    Int(i64),
136    Double(f64),
137    Float(f32),
138    String(String),
139    BooleanArray(Vec<bool>),
140    IntArray(Vec<i64>),
141    FloatArray(Vec<f32>),
142    DoubleArray(Vec<f64>),
143    StringArray(Vec<String>),
144    Raw(Box<Bytes>),
145    #[serde(skip_deserializing)]
146    Struct(
147        #[serde(skip)]
148        &'static str,
149        Box<Bytes>
150    ),
151    #[serde(skip_deserializing)]
152    Protobuf(
153        #[serde(skip)]
154        &'static FileDescriptorProto,
155        Box<Bytes>
156    ),
157}
158impl Display for FrcValue {
159    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
160        match self {
161            FrcValue::Void => write!(f, "Void"),
162            FrcValue::Boolean(v) => write!(f, "{}", v),
163            FrcValue::Int(v) => write!(f, "{}", v),
164            FrcValue::Double(v) => write!(f, "{}", v),
165            FrcValue::Float(v) => write!(f, "{}", v),
166            FrcValue::String(v) => write!(f, "{}", v),
167            FrcValue::BooleanArray(v) => write!(f, "{:?}", v),
168            FrcValue::IntArray(v) => write!(f, "{:?}", v),
169            FrcValue::FloatArray(v) => write!(f, "{:?}", v),
170            FrcValue::DoubleArray(v) => write!(f, "{:?}", v),
171            FrcValue::StringArray(v) => write!(f, "{:?}", v),
172            FrcValue::Raw(v) => write!(f, "{:?}", v),
173            FrcValue::r#Struct(name, data) => write!(f, "Struct({}):{:?}", name, data),
174            FrcValue::Protobuf(proto, data) => write!(
175                f, "Protobuf({}):{:?}",
176                proto.name.clone().unwrap_or("unknown".into()),
177                data
178            ),
179        }
180    }
181}
182impl Hash for FrcValue {
183    fn hash<H: Hasher>(&self, state: &mut H) {
184        match self {
185            FrcValue::Void => {}
186            FrcValue::Boolean(v) => v.hash(state),
187            FrcValue::Int(v) => v.hash(state),
188            FrcValue::Double(v) => v.to_bits().hash(state),
189            FrcValue::Float(v) => v.to_bits().hash(state),
190            FrcValue::String(v) => v.hash(state),
191            FrcValue::BooleanArray(v) => v.hash(state),
192            FrcValue::IntArray(v) => v.hash(state),
193            FrcValue::FloatArray(v) => v.iter().for_each(|v| v.to_bits().hash(state)),
194            FrcValue::DoubleArray(v) => v.iter().for_each(|v| v.to_bits().hash(state)),
195            FrcValue::StringArray(v) => v.hash(state),
196            FrcValue::Raw(v) => v.hash(state),
197            FrcValue::r#Struct(name, data) => {
198                name.hash(state);
199                data.hash(state);
200            }
201            FrcValue::Protobuf(proto, data) => {
202                proto.name.hash(state);
203                data.hash(state);
204            }
205        }
206    }
207}
208impl FrcValue {
209    ///Returns the type enum of the value, a more memory efficient way of checking the type
210    pub fn get_type(&self) -> FrcType {
211        match self {
212            FrcValue::Void => FrcType::Void,
213            FrcValue::Boolean(_) => FrcType::Boolean,
214            FrcValue::Int(_) => FrcType::Int,
215            FrcValue::Double(_) => FrcType::Double,
216            FrcValue::Float(_) => FrcType::Float,
217            FrcValue::String(_) => FrcType::String,
218            FrcValue::BooleanArray(_) => FrcType::BoolArray,
219            FrcValue::IntArray(_) => FrcType::IntArray,
220            FrcValue::FloatArray(_) => FrcType::FloatArray,
221            FrcValue::DoubleArray(_) => FrcType::DoubleArray,
222            FrcValue::StringArray(_) => FrcType::StringArray,
223            FrcValue::Raw(_) => FrcType::Raw,
224            FrcValue::r#Struct(_, _) => FrcType::Struct,
225            FrcValue::Protobuf(_, _) => FrcType::Protobuf,
226        }
227    }
228    ///Creates an empty Binary
229    pub fn empty() -> Self {
230        Self::Void
231    }
232    ///always false if not binary, array or string
233    pub fn is_empty(&self) -> bool {
234        match self {
235            FrcValue::Void => true,
236            FrcValue::String(v) => v.is_empty(),
237            FrcValue::BooleanArray(v) => v.is_empty(),
238            FrcValue::IntArray(v) => v.is_empty(),
239            FrcValue::DoubleArray(v) => v.is_empty(),
240            FrcValue::FloatArray(v) => v.is_empty(),
241            FrcValue::StringArray(v) => v.is_empty(),
242            FrcValue::Raw(v) => v.is_empty(),
243            FrcValue::r#Struct(_, v) => v.is_empty(),
244            FrcValue::Protobuf(_, v) => v.is_empty(),
245            _ => false,
246        }
247    }
248    ///Binary is false
249    pub fn is_array(&self) -> bool {
250        match self {
251            FrcValue::BooleanArray(_) => true,
252            FrcValue::IntArray(_) => true,
253            FrcValue::DoubleArray(_) => true,
254            FrcValue::FloatArray(_) => true,
255            FrcValue::StringArray(_) => true,
256            _ => false,
257        }
258    }
259    /// Consumes itself to a timestamped value with the current timestamp
260    pub fn to_timestamped_now(self) -> FrcTimestampedValue {
261        FrcTimestampedValue::new(now(), self)
262    }
263    /// Consumes itself to a timestamped value with the given timestamp
264    pub fn to_timestamped(self, timestamp: FrcTimestamp) -> FrcTimestampedValue {
265        FrcTimestampedValue::new(timestamp, self)
266    }
267    /// Clones itself to a timestamped value with the current timestamp
268    pub fn as_timestamped_now(&self) -> FrcTimestampedValue {
269        FrcTimestampedValue::new(now(), self.clone())
270    }
271    /// Clones itself to a timestamped value with the given timestamp
272    pub fn as_timestamped(&self, timestamp: FrcTimestamp) -> FrcTimestampedValue {
273        FrcTimestampedValue::new(timestamp, self.clone())
274    }
275    pub fn to_tagged(self) -> TaggedValue {
276        TaggedValue {
277            r#type: self.get_type(),
278            value: self,
279        }
280    }
281    /// Creates a default value based on the type
282    ///
283    /// Types that will return none:
284    ///     - Void
285    ///     - Struct
286    ///     - Protobuf
287    pub fn default_value(r#type: FrcType) -> Option<Self> {
288        match r#type {
289            FrcType::Void => None,
290            FrcType::Boolean => Some(FrcValue::Boolean(false)),
291            FrcType::Int => Some(FrcValue::Int(0)),
292            FrcType::Double => Some(FrcValue::Double(0.0)),
293            FrcType::Float => Some(FrcValue::Float(0.0)),
294            FrcType::String => Some(FrcValue::String(String::new())),
295            FrcType::BoolArray => Some(FrcValue::BooleanArray(Vec::new())),
296            FrcType::IntArray => Some(FrcValue::IntArray(Vec::new())),
297            FrcType::FloatArray => Some(FrcValue::FloatArray(Vec::new())),
298            FrcType::DoubleArray => Some(FrcValue::DoubleArray(Vec::new())),
299            FrcType::StringArray => Some(FrcValue::StringArray(Vec::new())),
300            FrcType::Raw => Some(FrcValue::Raw(Box::new(Bytes::new()))),
301            FrcType::Struct => None,
302            FrcType::Protobuf => None,
303        }
304    }
305}
306
307#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash)]
308pub struct TaggedValue {
309    #[serde(rename = "type")]
310    pub r#type: FrcType,
311    pub value: FrcValue,
312}
313impl Display for TaggedValue {
314    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
315        write!(f, "{}({})", self.r#type, self.value)
316    }
317}
318
319#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash)]
320pub struct FrcTimestampedValue {
321    pub timestamp: FrcTimestamp,
322    pub value: FrcValue,
323}
324impl Display for FrcTimestampedValue {
325    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
326        write!(f, "{} at {}", self.value, self.timestamp)
327    }
328}
329impl FrcTimestampedValue {
330    pub fn new(timestamp: FrcTimestamp, value: FrcValue) -> Self {
331        Self { timestamp, value }
332    }
333    pub fn get_type(&self) -> FrcType {
334        self.value.get_type()
335    }
336    pub fn is_empty(&self) -> bool {
337        self.value.is_empty()
338    }
339    pub fn is_array(&self) -> bool {
340        self.value.is_array()
341    }
342    pub fn is_after_timestamp(&self, timestamp: FrcTimestamp) -> bool {
343        self.timestamp > timestamp
344    }
345    pub fn is_after_other(&self, other: &Self) -> bool {
346        self.timestamp > other.timestamp
347    }
348    pub fn is_before_timestamp(&self, timestamp: FrcTimestamp) -> bool {
349        self.timestamp < timestamp
350    }
351    pub fn is_before_other(&self, other: &Self) -> bool {
352        self.timestamp < other.timestamp
353    }
354    pub fn replace_timestamp(&mut self, timestamp: FrcTimestamp) {
355        self.timestamp = timestamp;
356    }
357    pub fn replace_value(&mut self, value: FrcValue) {
358        self.value = value;
359    }
360    pub fn replace(&mut self, other: Self) {
361        self.timestamp = other.timestamp;
362        self.value = other.value;
363    }
364}
365
366#[derive(Debug, Clone, Serialize, Deserialize)]
367pub struct FrcTimeline(Vec<FrcTimestampedValue>);
368
369impl IntoIterator for FrcTimeline {
370    type Item = FrcTimestampedValue;
371    type IntoIter = std::vec::IntoIter<Self::Item>;
372    fn into_iter(self) -> Self::IntoIter {
373        self.0.into_iter()
374    }
375}
376
377impl FrcTimeline {
378    pub fn new() -> Self {
379        Self(Vec::new())
380    }
381    pub fn from_vec_sorted(vec: Vec<FrcTimestampedValue>) -> Self {
382        Self(vec)
383    }
384    pub fn from_vec(mut vec: Vec<FrcTimestampedValue>) -> Self {
385        vec.sort_by(|a, b| a.timestamp.cmp(&b.timestamp));
386        Self(vec)
387    }
388    pub fn to_vec(self) -> Vec<FrcTimestampedValue> {
389        self.0
390    }
391    pub fn is_all_same_type(&self) -> bool {
392        if self.0.is_empty() {
393            return true;
394        }
395        let first_type = self.0[0].get_type();
396        self.0.iter().all(|v| v.get_type() == first_type)
397    }
398    pub fn is_all_same_type_as(&self, other: &FrcType) -> bool {
399        if self.0.is_empty() {
400            return true;
401        }
402        self.0.iter().all(|v| v.get_type() == *other)
403    }
404    pub fn is_empty(&self) -> bool {
405        self.0.is_empty()
406    }
407    pub fn len(&self) -> usize {
408        self.0.len()
409    }
410    /// if closest above will get the value with the closest timestamp that is after the given timestamp
411    /// if closest above is false, will get the value with the closest timestamp that is before the given timestamp
412    pub fn get_by_timestamp(
413        &self,
414        timestamp: u64,
415        closest_after: bool,
416    ) -> Option<&FrcTimestampedValue> {
417        if closest_after {
418            if timestamp < self.0[0].timestamp {
419                return None;
420            }
421        } else {
422            if timestamp > self.0[self.0.len() - 1].timestamp {
423                return None;
424            }
425        }
426        //use a bisect algorithm to find the closest value
427        let mut low = 0;
428        let mut high = self.0.len() - 1;
429        while low <= high {
430            let mid = (low + high) / 2;
431            if self.0[mid].timestamp < timestamp {
432                low = mid + 1;
433            } else if self.0[mid].timestamp > timestamp {
434                high = mid - 1;
435            } else {
436                return Some(&self.0[mid]);
437            }
438        }
439        if low == self.0.len() {
440            return None;
441        }
442        if closest_after {
443            Some(&self.0[low])
444        } else {
445            Some(&self.0[low - 1])
446        }
447    }
448}
449
450#[derive(Debug, Clone, Serialize, Deserialize)]
451pub struct FrcTableInstant {
452    #[serde(flatten)]
453    pub values: HashMap<String, FrcTimestampedValue>, //just now
454}
455impl Display for FrcTableInstant {
456    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
457        write!(f, "{{")?;
458        for (i, (k, v)) in self.values.iter().enumerate() {
459            if i != 0 {
460                write!(f, ", ")?;
461            }
462            write!(f, "{}: {}", k, v)?;
463        }
464        write!(f, "}}")
465    }
466}
467impl FrcTableInstant {
468    pub fn new_slim() -> Self {
469        Self {
470            values: HashMap::new(),
471        }
472    }
473    pub fn new() -> Self {
474        Self {
475            values: HashMap::new(),
476        }
477    }
478    pub fn from_tuples(mut tuples: Vec<(impl ToString, FrcTimestampedValue)>) -> Self {
479        let mut values = HashMap::new();
480        tuples.reverse();
481        for (k, v) in tuples {
482            values.insert(k.to_string(), v);
483        }
484        Self { values }
485    }
486    pub fn set_field(&mut self, name: impl ToString, value: FrcTimestampedValue) {
487        self.values.insert(name.to_string(), value);
488    }
489}
490
491#[derive(Debug, Clone, Serialize, Deserialize, Default)]
492pub struct FrcTableHistory {
493    #[serde(flatten)]
494    pub values: HashMap<String, FrcTimeline>, //all values that have occured
495}
496
497#[derive(Debug, Clone, Serialize, Deserialize)]
498#[serde(tag = "type", content = "table", rename_all = "lowercase")]
499pub enum FrcTable {
500    Instant(FrcTableInstant),
501    History(FrcTableHistory),
502}