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}