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}