1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
use crate::{prelude::*, Error};
use indexmap::Equivalent;
use std::{
    cmp::Ordering,
    fmt,
    hash::{Hash, Hasher},
};

/// The key type used by [ValueMap](crate::ValueMap)
///
/// Only hashable values can be used as keys, see [KValue::is_hashable]
#[derive(Clone)]
pub struct ValueKey(KValue);

impl ValueKey {
    /// Returns a reference to the key's value
    pub fn value(&self) -> &KValue {
        &self.0
    }
}

impl TryFrom<KValue> for ValueKey {
    type Error = Error;

    fn try_from(value: KValue) -> Result<Self, Self::Error> {
        if value.is_hashable() {
            Ok(Self(value))
        } else {
            runtime_error!("Only hashable values can be used as value keys")
        }
    }
}

impl PartialEq for ValueKey {
    fn eq(&self, other: &Self) -> bool {
        use KValue::*;

        match (&self.0, &other.0) {
            (Number(a), Number(b)) => a == b,
            (Bool(a), Bool(b)) => a == b,
            (Str(a), Str(b)) => a == b,
            (Range(a), Range(b)) => a == b,
            (Null, Null) => true,
            (Tuple(a), Tuple(b)) => {
                a.len() == b.len()
                    && a.iter()
                        .zip(b.iter())
                        .all(|(value_a, value_b)| Self(value_a.clone()) == Self(value_b.clone()))
            }
            _ => false,
        }
    }
}
impl Eq for ValueKey {}

impl Hash for ValueKey {
    fn hash<H: Hasher>(&self, state: &mut H) {
        use KValue::*;

        match &self.0 {
            Null => {}
            Bool(b) => b.hash(state),
            Number(n) => n.hash(state),
            Str(s) => s.hash(state),
            Range(r) => r.hash(state),
            Tuple(t) => {
                for value in t.iter() {
                    Self(value.clone()).hash(state)
                }
            }
            _ => {}
        }
    }
}

impl PartialOrd for ValueKey {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        use KValue::*;

        match (&self.0, &other.0) {
            (Null, Null) => Some(Ordering::Equal),
            (Null, _) => Some(Ordering::Less),
            (_, Null) => Some(Ordering::Greater),
            (Number(a), Number(b)) => a.partial_cmp(b),
            (Str(a), Str(b)) => a.partial_cmp(b),
            (Tuple(a), Tuple(b)) => match a.len().cmp(&b.len()) {
                Ordering::Equal => {
                    for (value_a, value_b) in a.iter().zip(b.iter()) {
                        // Only ValueRef-able values will be contained in a tuple that's made it
                        // into a ValueKey
                        match Self(value_a.clone()).partial_cmp(&Self(value_b.clone())) {
                            Some(Ordering::Equal) => {}
                            other => return other,
                        }
                    }
                    Some(Ordering::Equal)
                }
                other => Some(other),
            },
            _ => Some(Ordering::Equal),
        }
    }
}

impl fmt::Display for ValueKey {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        use KValue::*;

        match &self.0 {
            Null => f.write_str("null"),
            Bool(b) => write!(f, "{b}"),
            Number(n) => write!(f, "{n}"),
            Range(r) => write!(f, "{r}"),
            Str(s) => f.write_str(s),
            Tuple(t) => {
                f.write_str("(")?;
                for (i, value) in t.iter().enumerate() {
                    if i > 0 {
                        f.write_str(", ")?;
                    }
                    write!(f, "{}", Self(value.clone()))?;
                }
                f.write_str(")")
            }
            _ => Ok(()),
        }
    }
}

impl From<KString> for ValueKey {
    fn from(value: KString) -> Self {
        Self(KValue::Str(value))
    }
}

impl<T> From<T> for ValueKey
where
    KNumber: From<T>,
{
    fn from(value: T) -> Self {
        Self(KValue::Number(value.into()))
    }
}

impl From<&str> for ValueKey {
    fn from(value: &str) -> Self {
        Self(KValue::Str(value.into()))
    }
}

// Support efficient map lookups with &str
impl Equivalent<ValueKey> for str {
    fn equivalent(&self, other: &ValueKey) -> bool {
        match &other.0 {
            KValue::Str(s) => self == s.as_str(),
            _ => false,
        }
    }
}

impl Equivalent<ValueKey> for KString {
    fn equivalent(&self, other: &ValueKey) -> bool {
        match &other.0 {
            KValue::Str(s) => self == s,
            _ => false,
        }
    }
}