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