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
20pub 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#[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 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 pub fn empty() -> Self {
230 Self::Void
231 }
232 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 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 pub fn to_timestamped_now(self) -> FrcTimestampedValue {
261 FrcTimestampedValue::new(now(), self)
262 }
263 pub fn to_timestamped(self, timestamp: FrcTimestamp) -> FrcTimestampedValue {
265 FrcTimestampedValue::new(timestamp, self)
266 }
267 pub fn as_timestamped_now(&self) -> FrcTimestampedValue {
269 FrcTimestampedValue::new(now(), self.clone())
270 }
271 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 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 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 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>, }
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>, }
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}