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