1use num_bigint::BigInt;
10use num_traits::{Signed, ToPrimitive};
11use std::cmp::Ordering;
12use std::collections::{BTreeMap, BTreeSet};
13use std::fmt;
14
15pub use crate::value_impls::{from_value, to_value};
16
17use crate::error::{Error, ErrorCode};
18
19#[derive(Clone, Debug, PartialEq)]
28pub enum Value {
29 None,
31 Bool(bool),
33 I64(i64),
35 Int(BigInt),
37 F64(f64),
39 Bytes(Vec<u8>),
41 String(String),
43 List(Vec<Value>),
45 Tuple(Vec<Value>),
47 Set(BTreeSet<HashableValue>),
49 FrozenSet(BTreeSet<HashableValue>),
51 Dict(BTreeMap<HashableValue, Value>),
53}
54
55#[derive(Clone, Debug)]
63pub enum HashableValue {
64 None,
66 Bool(bool),
68 I64(i64),
70 Int(BigInt),
72 F64(f64),
74 Bytes(Vec<u8>),
76 String(String),
78 Tuple(Vec<HashableValue>),
80 FrozenSet(BTreeSet<HashableValue>),
82}
83
84fn values_to_hashable(values: Vec<Value>) -> Result<Vec<HashableValue>, Error> {
85 values.into_iter().map(Value::into_hashable).collect()
86}
87
88fn hashable_to_values(values: Vec<HashableValue>) -> Vec<Value> {
89 values.into_iter().map(HashableValue::into_value).collect()
90}
91
92impl Value {
93 pub fn into_hashable(self) -> Result<HashableValue, Error> {
96 match self {
97 Value::None => Ok(HashableValue::None),
98 Value::Bool(b) => Ok(HashableValue::Bool(b)),
99 Value::I64(i) => Ok(HashableValue::I64(i)),
100 Value::Int(i) => Ok(HashableValue::Int(i)),
101 Value::F64(f) => Ok(HashableValue::F64(f)),
102 Value::Bytes(b) => Ok(HashableValue::Bytes(b)),
103 Value::String(s) => Ok(HashableValue::String(s)),
104 Value::FrozenSet(v) => Ok(HashableValue::FrozenSet(v)),
105 Value::Tuple(v) => values_to_hashable(v).map(HashableValue::Tuple),
106 _ => Err(Error::Syntax(ErrorCode::ValueNotHashable)),
107 }
108 }
109}
110
111impl HashableValue {
112 pub fn into_value(self) -> Value {
114 match self {
115 HashableValue::None => Value::None,
116 HashableValue::Bool(b) => Value::Bool(b),
117 HashableValue::I64(i) => Value::I64(i),
118 HashableValue::Int(i) => Value::Int(i),
119 HashableValue::F64(f) => Value::F64(f),
120 HashableValue::Bytes(b) => Value::Bytes(b),
121 HashableValue::String(s) => Value::String(s),
122 HashableValue::FrozenSet(v) => Value::FrozenSet(v),
123 HashableValue::Tuple(v) => Value::Tuple(hashable_to_values(v)),
124 }
125 }
126}
127
128fn write_elements<'a, I, T>(
129 f: &mut fmt::Formatter, it: I, prefix: &'static str, suffix: &'static str, len: usize, always_comma: bool,
130) -> fmt::Result
131where
132 I: Iterator<Item = &'a T>,
133 T: fmt::Display + 'a,
134{
135 f.write_str(prefix)?;
136 for (i, item) in it.enumerate() {
137 if i < len - 1 || always_comma {
138 write!(f, "{}, ", item)?;
139 } else {
140 write!(f, "{}", item)?;
141 }
142 }
143 f.write_str(suffix)
144}
145
146impl fmt::Display for Value {
147 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 match *self {
149 Value::None => write!(f, "None"),
150 Value::Bool(b) => write!(f, "{}", if b { "True" } else { "False" }),
151 Value::I64(i) => write!(f, "{}", i),
152 Value::Int(ref i) => write!(f, "{}", i),
153 Value::F64(v) => write!(f, "{}", v),
154 Value::Bytes(ref b) => write!(f, "b{:?}", b), Value::String(ref s) => write!(f, "{:?}", s),
156 Value::List(ref v) => write_elements(f, v.iter(), "[", "]", v.len(), false),
157 Value::Tuple(ref v) => write_elements(f, v.iter(), "(", ")", v.len(), v.len() == 1),
158 Value::FrozenSet(ref v) => write_elements(f, v.iter(), "frozenset([", "])", v.len(), false),
159 Value::Set(ref v) => {
160 if v.is_empty() {
161 write!(f, "set()")
162 } else {
163 write_elements(f, v.iter(), "{", "}", v.len(), false)
164 }
165 }
166 Value::Dict(ref v) => {
167 write!(f, "{{")?;
168 for (i, (key, value)) in v.iter().enumerate() {
169 if i < v.len() - 1 {
170 write!(f, "{}: {}, ", key, value)?;
171 } else {
172 write!(f, "{}: {}", key, value)?;
173 }
174 }
175 write!(f, "}}")
176 }
177 }
178 }
179}
180
181impl fmt::Display for HashableValue {
182 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
183 match *self {
184 HashableValue::None => write!(f, "None"),
185 HashableValue::Bool(b) => write!(f, "{}", if b { "True" } else { "False" }),
186 HashableValue::I64(i) => write!(f, "{}", i),
187 HashableValue::Int(ref i) => write!(f, "{}", i),
188 HashableValue::F64(v) => write!(f, "{}", v),
189 HashableValue::Bytes(ref b) => write!(f, "b{:?}", b), HashableValue::String(ref s) => write!(f, "{:?}", s),
191 HashableValue::Tuple(ref v) => write_elements(f, v.iter(), "(", ")", v.len(), v.len() == 1),
192 HashableValue::FrozenSet(ref v) => {
193 write_elements(f, v.iter(), "frozenset([", "])", v.len(), false)
194 }
195 }
196 }
197}
198
199impl PartialEq for HashableValue {
200 fn eq(&self, other: &HashableValue) -> bool {
201 self.cmp(other) == Ordering::Equal
202 }
203}
204
205impl Eq for HashableValue {}
206
207impl PartialOrd for HashableValue {
208 fn partial_cmp(&self, other: &HashableValue) -> Option<Ordering> {
209 Some(self.cmp(other))
210 }
211}
212
213impl Ord for HashableValue {
223 fn cmp(&self, other: &HashableValue) -> Ordering {
224 use self::HashableValue::*;
225 match *self {
226 None => match *other {
227 None => Ordering::Equal,
228 _ => Ordering::Less,
229 },
230 Bool(b) => match *other {
231 None => Ordering::Greater,
232 Bool(b2) => b.cmp(&b2),
233 I64(i2) => (b as i64).cmp(&i2),
234 Int(ref bi) => BigInt::from(b as i64).cmp(bi),
235 F64(f) => float_ord(b as i64 as f64, f),
236 _ => Ordering::Less,
237 },
238 I64(i) => match *other {
239 None => Ordering::Greater,
240 Bool(b) => i.cmp(&(b as i64)),
241 I64(i2) => i.cmp(&i2),
242 Int(ref bi) => BigInt::from(i).cmp(bi),
243 F64(f) => float_ord(i as f64, f),
244 _ => Ordering::Less,
245 },
246 Int(ref bi) => match *other {
247 None => Ordering::Greater,
248 Bool(b) => bi.cmp(&BigInt::from(b as i64)),
249 I64(i) => bi.cmp(&BigInt::from(i)),
250 Int(ref bi2) => bi.cmp(bi2),
251 F64(f) => float_bigint_ord(bi, f),
252 _ => Ordering::Less,
253 },
254 F64(f) => match *other {
255 None => Ordering::Greater,
256 Bool(b) => float_ord(f, b as i64 as f64),
257 I64(i) => float_ord(f, i as f64),
258 Int(ref bi) => BigInt::from(f as i64).cmp(bi),
259 F64(f2) => float_ord(f, f2),
260 _ => Ordering::Less,
261 },
262 Bytes(ref bs) => match *other {
263 String(_) | FrozenSet(_) | Tuple(_) => Ordering::Less,
264 Bytes(ref bs2) => bs.cmp(bs2),
265 _ => Ordering::Greater,
266 },
267 String(ref s) => match *other {
268 FrozenSet(_) | Tuple(_) => Ordering::Less,
269 String(ref s2) => s.cmp(s2),
270 _ => Ordering::Greater,
271 },
272 FrozenSet(ref s) => match *other {
273 Tuple(_) => Ordering::Less,
274 FrozenSet(ref s2) => s.cmp(s2),
275 _ => Ordering::Greater,
276 },
277 Tuple(ref t) => match *other {
278 Tuple(ref t2) => t.cmp(t2),
279 _ => Ordering::Greater,
280 },
281 }
282 }
283}
284
285fn float_ord(f: f64, g: f64) -> Ordering {
287 match f.partial_cmp(&g) {
288 Some(o) => o,
289 None => Ordering::Less,
290 }
291}
292
293fn float_bigint_ord(bi: &BigInt, g: f64) -> Ordering {
295 match bi.to_f64() {
296 Some(f) => float_ord(f, g),
297 None => {
298 if bi.is_positive() {
299 Ordering::Greater
300 } else {
301 Ordering::Less
302 }
303 }
304 }
305}