1 use std::cmp::Ordering;
2 use std::fmt;
3 
4 use kstring::KStringCow;
5 
6 use super::DisplayCow;
7 use super::State;
8 use super::Value;
9 use crate::model::ArrayView;
10 use crate::model::ObjectView;
11 use crate::model::ScalarCow;
12 
13 /// Accessor for Values.
14 pub trait ValueView: fmt::Debug {
15     /// Get a `Debug` representation
as_debug(&self) -> &dyn fmt::Debug16     fn as_debug(&self) -> &dyn fmt::Debug;
17 
18     /// A `Display` for a `BoxedValue` rendered for the user.
render(&self) -> DisplayCow<'_>19     fn render(&self) -> DisplayCow<'_>;
20     /// A `Display` for a `Value` as source code.
source(&self) -> DisplayCow<'_>21     fn source(&self) -> DisplayCow<'_>;
22     /// Report the data type (generally for error reporting).
type_name(&self) -> &'static str23     fn type_name(&self) -> &'static str;
24     /// Query the value's state
query_state(&self, state: State) -> bool25     fn query_state(&self, state: State) -> bool;
26 
27     /// Interpret as a string.
to_kstr(&self) -> KStringCow<'_>28     fn to_kstr(&self) -> KStringCow<'_>;
29     /// Convert to an owned type.
to_value(&self) -> Value30     fn to_value(&self) -> Value;
31 
32     /// Extracts the scalar value if it is a scalar.
as_scalar(&self) -> Option<ScalarCow<'_>>33     fn as_scalar(&self) -> Option<ScalarCow<'_>> {
34         None
35     }
36     /// Tests whether this value is a scalar
is_scalar(&self) -> bool37     fn is_scalar(&self) -> bool {
38         self.as_scalar().is_some()
39     }
40 
41     /// Extracts the array value if it is an array.
as_array(&self) -> Option<&dyn ArrayView>42     fn as_array(&self) -> Option<&dyn ArrayView> {
43         None
44     }
45     /// Tests whether this value is an array
is_array(&self) -> bool46     fn is_array(&self) -> bool {
47         self.as_array().is_some()
48     }
49 
50     /// Extracts the object value if it is a object.
as_object(&self) -> Option<&dyn ObjectView>51     fn as_object(&self) -> Option<&dyn ObjectView> {
52         None
53     }
54     /// Tests whether this value is an object
is_object(&self) -> bool55     fn is_object(&self) -> bool {
56         self.as_object().is_some()
57     }
58 
59     /// Extracts the state if it is one
as_state(&self) -> Option<State>60     fn as_state(&self) -> Option<State> {
61         None
62     }
63     /// Tests whether this value is state
is_state(&self) -> bool64     fn is_state(&self) -> bool {
65         self.as_state().is_some()
66     }
67 
68     /// Tests whether this value is nil
69     ///
70     /// See the [Stack overflow table](https://stackoverflow.com/questions/885414/a-concise-explanation-of-nil-v-empty-v-blank-in-ruby-on-rails)
is_nil(&self) -> bool71     fn is_nil(&self) -> bool {
72         false
73     }
74 }
75 
76 impl<'v, V: ValueView + ?Sized> ValueView for &'v V {
as_debug(&self) -> &dyn fmt::Debug77     fn as_debug(&self) -> &dyn fmt::Debug {
78         <V as ValueView>::as_debug(self)
79     }
80 
render(&self) -> DisplayCow<'_>81     fn render(&self) -> DisplayCow<'_> {
82         <V as ValueView>::render(self)
83     }
source(&self) -> DisplayCow<'_>84     fn source(&self) -> DisplayCow<'_> {
85         <V as ValueView>::source(self)
86     }
type_name(&self) -> &'static str87     fn type_name(&self) -> &'static str {
88         <V as ValueView>::type_name(self)
89     }
query_state(&self, state: State) -> bool90     fn query_state(&self, state: State) -> bool {
91         <V as ValueView>::query_state(self, state)
92     }
93 
to_kstr(&self) -> KStringCow<'_>94     fn to_kstr(&self) -> KStringCow<'_> {
95         <V as ValueView>::to_kstr(self)
96     }
to_value(&self) -> Value97     fn to_value(&self) -> Value {
98         <V as ValueView>::to_value(self)
99     }
100 
as_scalar(&self) -> Option<ScalarCow<'_>>101     fn as_scalar(&self) -> Option<ScalarCow<'_>> {
102         <V as ValueView>::as_scalar(self)
103     }
104 
as_array(&self) -> Option<&dyn ArrayView>105     fn as_array(&self) -> Option<&dyn ArrayView> {
106         <V as ValueView>::as_array(self)
107     }
108 
as_object(&self) -> Option<&dyn ObjectView>109     fn as_object(&self) -> Option<&dyn ObjectView> {
110         <V as ValueView>::as_object(self)
111     }
112 
as_state(&self) -> Option<State>113     fn as_state(&self) -> Option<State> {
114         <V as ValueView>::as_state(self)
115     }
116 
is_nil(&self) -> bool117     fn is_nil(&self) -> bool {
118         <V as ValueView>::is_nil(self)
119     }
120 }
121 
122 static NIL: Value = Value::Nil;
123 
124 impl<T: ValueView> ValueView for Option<T> {
as_debug(&self) -> &dyn fmt::Debug125     fn as_debug(&self) -> &dyn fmt::Debug {
126         self
127     }
128 
render(&self) -> DisplayCow<'_>129     fn render(&self) -> DisplayCow<'_> {
130         forward(self).render()
131     }
source(&self) -> DisplayCow<'_>132     fn source(&self) -> DisplayCow<'_> {
133         forward(self).source()
134     }
type_name(&self) -> &'static str135     fn type_name(&self) -> &'static str {
136         forward(self).type_name()
137     }
query_state(&self, state: State) -> bool138     fn query_state(&self, state: State) -> bool {
139         forward(self).query_state(state)
140     }
141 
to_kstr(&self) -> KStringCow<'_>142     fn to_kstr(&self) -> KStringCow<'_> {
143         forward(self).to_kstr()
144     }
to_value(&self) -> Value145     fn to_value(&self) -> Value {
146         forward(self).to_value()
147     }
148 
as_scalar(&self) -> Option<ScalarCow<'_>>149     fn as_scalar(&self) -> Option<ScalarCow<'_>> {
150         forward(self).as_scalar()
151     }
152 
as_array(&self) -> Option<&dyn ArrayView>153     fn as_array(&self) -> Option<&dyn ArrayView> {
154         forward(self).as_array()
155     }
156 
as_object(&self) -> Option<&dyn ObjectView>157     fn as_object(&self) -> Option<&dyn ObjectView> {
158         forward(self).as_object()
159     }
160 
as_state(&self) -> Option<State>161     fn as_state(&self) -> Option<State> {
162         forward(self).as_state()
163     }
164 
is_nil(&self) -> bool165     fn is_nil(&self) -> bool {
166         forward(self).is_nil()
167     }
168 }
169 
forward(o: &Option<impl ValueView>) -> &dyn ValueView170 fn forward(o: &Option<impl ValueView>) -> &dyn ValueView {
171     o.as_ref()
172         .map(|v| v as &dyn ValueView)
173         .unwrap_or(&NIL as &dyn ValueView)
174 }
175 
176 /// `Value` comparison semantics for types implementing `ValueView`.
177 #[derive(Copy, Clone, Debug)]
178 pub struct ValueViewCmp<'v>(&'v dyn ValueView);
179 
180 impl<'v> ValueViewCmp<'v> {
181     /// `Value` comparison semantics for types implementing `ValueView`.
new(v: &dyn ValueView) -> ValueViewCmp<'_>182     pub fn new(v: &dyn ValueView) -> ValueViewCmp<'_> {
183         ValueViewCmp(v)
184     }
185 }
186 
187 impl<'v> PartialEq<ValueViewCmp<'v>> for ValueViewCmp<'v> {
eq(&self, other: &Self) -> bool188     fn eq(&self, other: &Self) -> bool {
189         value_eq(self.0, other.0)
190     }
191 }
192 
193 impl<'v> PartialEq<i64> for ValueViewCmp<'v> {
eq(&self, other: &i64) -> bool194     fn eq(&self, other: &i64) -> bool {
195         super::value_eq(self.0, other)
196     }
197 }
198 
199 impl<'v> PartialEq<f64> for ValueViewCmp<'v> {
eq(&self, other: &f64) -> bool200     fn eq(&self, other: &f64) -> bool {
201         super::value_eq(self.0, other)
202     }
203 }
204 
205 impl<'v> PartialEq<bool> for ValueViewCmp<'v> {
eq(&self, other: &bool) -> bool206     fn eq(&self, other: &bool) -> bool {
207         super::value_eq(self.0, other)
208     }
209 }
210 
211 impl<'v> PartialEq<crate::model::scalar::DateTime> for ValueViewCmp<'v> {
eq(&self, other: &crate::model::scalar::DateTime) -> bool212     fn eq(&self, other: &crate::model::scalar::DateTime) -> bool {
213         super::value_eq(self.0, other)
214     }
215 }
216 
217 impl<'v> PartialEq<crate::model::scalar::Date> for ValueViewCmp<'v> {
eq(&self, other: &crate::model::scalar::Date) -> bool218     fn eq(&self, other: &crate::model::scalar::Date) -> bool {
219         super::value_eq(self.0, other)
220     }
221 }
222 
223 impl<'v> PartialEq<str> for ValueViewCmp<'v> {
eq(&self, other: &str) -> bool224     fn eq(&self, other: &str) -> bool {
225         let other = KStringCow::from_ref(other);
226         super::value_eq(self.0, &other)
227     }
228 }
229 
230 impl<'v> PartialEq<&'v str> for ValueViewCmp<'v> {
eq(&self, other: &&str) -> bool231     fn eq(&self, other: &&str) -> bool {
232         super::value_eq(self.0, other)
233     }
234 }
235 
236 impl<'v> PartialEq<String> for ValueViewCmp<'v> {
eq(&self, other: &String) -> bool237     fn eq(&self, other: &String) -> bool {
238         self == other.as_str()
239     }
240 }
241 
242 impl<'v> PartialEq<kstring::KString> for ValueViewCmp<'v> {
eq(&self, other: &kstring::KString) -> bool243     fn eq(&self, other: &kstring::KString) -> bool {
244         super::value_eq(self.0, &other.as_ref())
245     }
246 }
247 
248 impl<'v> PartialEq<kstring::KStringRef<'v>> for ValueViewCmp<'v> {
eq(&self, other: &kstring::KStringRef<'v>) -> bool249     fn eq(&self, other: &kstring::KStringRef<'v>) -> bool {
250         super::value_eq(self.0, other)
251     }
252 }
253 
254 impl<'v> PartialEq<kstring::KStringCow<'v>> for ValueViewCmp<'v> {
eq(&self, other: &kstring::KStringCow<'v>) -> bool255     fn eq(&self, other: &kstring::KStringCow<'v>) -> bool {
256         super::value_eq(self.0, other)
257     }
258 }
259 
260 impl<'v> PartialOrd<ValueViewCmp<'v>> for ValueViewCmp<'v> {
partial_cmp(&self, other: &Self) -> Option<Ordering>261     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
262         value_cmp(self.0, other.0)
263     }
264 }
265 
value_eq(lhs: &dyn ValueView, rhs: &dyn ValueView) -> bool266 pub(crate) fn value_eq(lhs: &dyn ValueView, rhs: &dyn ValueView) -> bool {
267     if let (Some(x), Some(y)) = (lhs.as_array(), rhs.as_array()) {
268         if x.size() != y.size() {
269             return false;
270         }
271         return x.values().zip(y.values()).all(|(x, y)| value_eq(x, y));
272     }
273 
274     if let (Some(x), Some(y)) = (lhs.as_object(), rhs.as_object()) {
275         if x.size() != y.size() {
276             return false;
277         }
278         return x
279             .iter()
280             .all(|(key, value)| y.get(key.as_str()).map_or(false, |v| value_eq(v, value)));
281     }
282 
283     if lhs.is_nil() && rhs.is_nil() {
284         return true;
285     }
286 
287     if let Some(state) = lhs.as_state() {
288         return rhs.query_state(state);
289     } else if let Some(state) = rhs.as_state() {
290         return lhs.query_state(state);
291     }
292 
293     match (lhs.as_scalar(), rhs.as_scalar()) {
294         (Some(x), Some(y)) => return x == y,
295         (None, None) => (),
296         // encode Ruby truthiness: all values except false and nil are true
297         (Some(x), _) => {
298             if rhs.is_nil() {
299                 return !x.to_bool().unwrap_or(true);
300             } else {
301                 return x.to_bool().unwrap_or(false);
302             }
303         }
304         (_, Some(x)) => {
305             if lhs.is_nil() {
306                 return !x.to_bool().unwrap_or(true);
307             } else {
308                 return x.to_bool().unwrap_or(false);
309             }
310         }
311     }
312 
313     false
314 }
315 
value_cmp(lhs: &dyn ValueView, rhs: &dyn ValueView) -> Option<Ordering>316 pub(crate) fn value_cmp(lhs: &dyn ValueView, rhs: &dyn ValueView) -> Option<Ordering> {
317     if let (Some(x), Some(y)) = (lhs.as_scalar(), rhs.as_scalar()) {
318         return x.partial_cmp(&y);
319     }
320 
321     if let (Some(x), Some(y)) = (lhs.as_array(), rhs.as_array()) {
322         return x
323             .values()
324             .map(|v| ValueViewCmp(v))
325             .partial_cmp(y.values().map(|v| ValueViewCmp(v)));
326     }
327 
328     if let (Some(x), Some(y)) = (lhs.as_object(), rhs.as_object()) {
329         return x
330             .iter()
331             .map(|(k, v)| (k, ValueViewCmp(v)))
332             .partial_cmp(y.iter().map(|(k, v)| (k, ValueViewCmp(v))));
333     }
334 
335     None
336 }
337 
338 #[cfg(test)]
339 mod test {
340     use super::*;
341 
342     #[test]
test_debug()343     fn test_debug() {
344         let scalar = 5;
345         println!("{:?}", scalar);
346         let view: &dyn ValueView = &scalar;
347         println!("{:?}", view);
348         let debug: &dyn fmt::Debug = view.as_debug();
349         println!("{:?}", debug);
350     }
351 }
352