bluejay_core/
value.rs

1use crate::AsIter;
2use enum_as_inner::EnumAsInner;
3use std::collections::HashMap;
4
5#[cfg(feature = "serde_json")]
6mod serde_json;
7
8pub trait ObjectValue<const CONST: bool>: std::fmt::Debug {
9    type Key: AsRef<str> + PartialEq + std::fmt::Debug;
10    type Value: Value<CONST, Object = Self>;
11    type Iterator<'a>: Iterator<Item = (&'a Self::Key, &'a Self::Value)>
12    where
13        Self: 'a;
14
15    fn iter(&self) -> Self::Iterator<'_>;
16}
17
18impl<
19        const CONST: bool,
20        K: AsRef<str> + PartialEq + std::fmt::Debug,
21        V: Value<CONST, Object = Vec<(K, V)>> + std::fmt::Debug,
22    > ObjectValue<CONST> for Vec<(K, V)>
23{
24    type Key = K;
25    type Value = V;
26    type Iterator<'a> =
27        std::iter::Map<std::slice::Iter<'a, (K, V)>, fn(&'a (K, V)) -> (&'a K, &'a V)> where Self: 'a;
28
29    fn iter(&self) -> Self::Iterator<'_> {
30        self.as_slice().iter().map(|(k, v)| (k, v))
31    }
32}
33
34pub trait ListValue<const CONST: bool>: AsIter<Item = Self::Value> + std::fmt::Debug {
35    type Value: Value<CONST, List = Self>;
36}
37
38impl<const CONST: bool, T: Value<CONST, List = Vec<T>> + std::fmt::Debug> ListValue<CONST>
39    for Vec<T>
40{
41    type Value = T;
42}
43
44pub trait Variable {
45    fn name(&self) -> &str;
46}
47
48impl<T: AsRef<str>> Variable for T {
49    fn name(&self) -> &str {
50        self.as_ref()
51    }
52}
53
54pub trait Value<const CONST: bool>: Sized {
55    type List: ListValue<CONST, Value = Self>;
56    type Object: ObjectValue<CONST, Value = Self>;
57    type Variable: Variable;
58
59    fn as_ref(&self) -> ValueReference<'_, CONST, Self>;
60
61    fn can_coerce_string_value_to_enum() -> bool {
62        false
63    }
64}
65
66pub trait ConstValue: Value<true> {}
67pub trait VariableValue: Value<false> {}
68
69impl<T: Value<true>> ConstValue for T {}
70impl<T: Value<false>> VariableValue for T {}
71
72#[derive(Debug, strum::IntoStaticStr, EnumAsInner)]
73#[strum(serialize_all = "lowercase")]
74pub enum ValueReference<'a, const CONST: bool, V: Value<CONST>> {
75    Variable(&'a V::Variable),
76    Integer(i32),
77    Float(f64),
78    String(&'a str),
79    Boolean(bool),
80    Null,
81    Enum(&'a str),
82    List(&'a V::List),
83    Object(&'a V::Object),
84}
85
86impl<'a, const CONST: bool, V: Value<CONST>> ValueReference<'a, CONST, V> {
87    pub fn variant(&self) -> &'static str {
88        self.into()
89    }
90}
91
92impl<'a, const CONST: bool, V: Value<CONST>> Clone for ValueReference<'a, CONST, V> {
93    fn clone(&self) -> Self {
94        *self
95    }
96}
97
98impl<'a, const CONST: bool, V: Value<CONST>> Copy for ValueReference<'a, CONST, V> {}
99
100impl<'a, const CONST: bool, V: Value<CONST>> std::cmp::PartialEq for ValueReference<'a, CONST, V> {
101    fn eq(&self, other: &Self) -> bool {
102        match self {
103            Self::Variable(v) => {
104                matches!(other, Self::Variable(other_v) if v.name() == other_v.name())
105            }
106            Self::Integer(i) => {
107                matches!(other, Self::Integer(other_i) if i == other_i)
108            }
109            Self::Float(f) => {
110                matches!(other, Self::Float(other_f) if f == other_f)
111            }
112            Self::String(s) => {
113                matches!(other, Self::String(other_s) if s == other_s)
114            }
115            Self::Boolean(b) => {
116                matches!(other, Self::Boolean(other_b) if b == other_b)
117            }
118            Self::Null => matches!(other, Self::Null),
119            Self::Enum(e) => matches!(other, Self::Enum(other_e) if e == other_e),
120            Self::List(l) => {
121                matches!(other, Self::List(other_l) if itertools::equal(l.iter().map(Value::as_ref), other_l.iter().map(Value::as_ref)))
122            }
123            Self::Object(o) => matches!(other, Self::Object(other_o) if {
124                let lhs: HashMap<&str, _> = HashMap::from_iter(o.iter().map(|(k, v)| (k.as_ref(), v.as_ref())));
125                let rhs: HashMap<&str, _> = HashMap::from_iter(other_o.iter().map(|(k, v)| (k.as_ref(), v.as_ref())));
126                lhs == rhs
127            }),
128        }
129    }
130}