pyth_lazer_protocol/
dynamic_value.rs

1use std::collections::BTreeMap;
2
3use crate::time::{DurationUs, TimestampUs};
4use anyhow::bail;
5use derive_more::From;
6use serde::{
7    ser::{SerializeMap, SerializeSeq},
8    Serialize,
9};
10
11#[derive(Debug, Clone, PartialEq, From)]
12pub enum DynamicValue {
13    String(String),
14    F64(f64),
15    U64(u64),
16    I64(i64),
17    Bool(bool),
18    Timestamp(TimestampUs),
19    Duration(DurationUs),
20    Bytes(Vec<u8>),
21    List(Vec<DynamicValue>),
22    Map(BTreeMap<String, DynamicValue>),
23}
24
25impl Serialize for DynamicValue {
26    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
27    where
28        S: serde::Serializer,
29    {
30        match self {
31            DynamicValue::String(v) => serializer.serialize_str(v),
32            DynamicValue::F64(v) => serializer.serialize_f64(*v),
33            DynamicValue::U64(v) => serializer.serialize_u64(*v),
34            DynamicValue::I64(v) => serializer.serialize_i64(*v),
35            DynamicValue::Bool(v) => serializer.serialize_bool(*v),
36            DynamicValue::Timestamp(v) => serializer.serialize_u64(v.as_micros()),
37            DynamicValue::Duration(v) => {
38                serializer.serialize_str(&humantime::format_duration((*v).into()).to_string())
39            }
40            DynamicValue::Bytes(v) => serializer.serialize_str(&hex::encode(v)),
41            DynamicValue::List(v) => {
42                let mut seq_serializer = serializer.serialize_seq(Some(v.len()))?;
43                for element in v {
44                    seq_serializer.serialize_element(element)?;
45                }
46                seq_serializer.end()
47            }
48            DynamicValue::Map(map) => {
49                let mut map_serializer = serializer.serialize_map(Some(map.len()))?;
50                for (k, v) in map {
51                    map_serializer.serialize_entry(k, v)?;
52                }
53                map_serializer.end()
54            }
55        }
56    }
57}
58
59impl DynamicValue {
60    pub fn is_str(&self, field_name: &str) -> anyhow::Result<()> {
61        match self {
62            DynamicValue::String(_) => Ok(()),
63            _ => bail!("invalid value type for {field_name}: expected String, got {self:?}"),
64        }
65    }
66}