evergreen/
value.rs

1//! Wrapper class for JsonValue's which may also contain IDL-blessed values,
2//! i.e. those that have an IDL class and a well-defined set of fields.
3
4// Values serialize and deserialize as JSON/JsonValue's and much of the
5// code here takes direct inspiration from from the implemention for:
6// <https://docs.rs/json/latest/json/enum.JsonValue.html>
7use crate as eg;
8use eg::idl;
9use eg::{EgError, EgResult};
10use json::JsonValue;
11use std::collections::HashMap;
12use std::fmt;
13use std::mem;
14use std::ops::{Index, IndexMut};
15use std::sync::Arc;
16
17/// Classname and payload fields for wire-protocol JSON values.
18const JSON_CLASS_KEY: &str = "__c";
19const JSON_PAYLOAD_KEY: &str = "__p";
20
21/// Key to store the classname when translating blessed EgValue's
22/// into flat hashes.
23const HASH_CLASSNAME_KEY: &str = "_classname";
24
25/// Macro for build EgValue::Hash's by leveraging the json::object! macro.
26///
27/// Panics if an attempt is made to build an EgValue::Blessed with
28/// an unknown class name or invalid field, which can only happen
29/// in practice if the caller defines the hash using the wire-level
30/// JSON_CLASS_KEY ("__c") and JSON_PAYLOAD_KEY ("__p") structure.
31///
32/// let h = eg::hash! {"hello": "errbody"};
33#[macro_export]
34macro_rules! hash {
35    ($($tts:tt)*) => {
36        match $crate::EgValue::from_json_value(json::object!($($tts)*)) {
37            Ok(v) => v,
38            Err(e) => {
39                // Unlikely to get here, but not impossible.
40                let msg = format!("eg::hash! {e}");
41                log::error!("{msg}");
42                panic!("{}", msg);
43            }
44        }
45    }
46}
47
48/// Macro for buildling EgValue::Blessed values by encoding the
49/// classname directly in the hash via the HASH_CLASSNAME_KEY key
50/// ("_classname").
51///
52/// Returns `Result<EgValue>` to accommodate invalid classnames or fields.
53/// Becuase of this, the macro only works within functions that return
54/// EgResult.
55///
56/// let v = eg::blessed! {
57///     "_classname": "aou",
58///     "id": 123,
59///     "name": "TEST",
60///     "shortname": "FOO",
61/// }?;
62#[macro_export]
63macro_rules! blessed {
64    ($($tts:tt)*) => {{
65        match $crate::EgValue::from_json_value(json::object!($($tts)*)) {
66            Ok(mut v) => {
67                v.from_classed_hash()?;
68                Ok(v)
69            },
70            Err(e) => {
71                log::error!("eg::hash! {e}");
72                Err(e)
73            }
74        }
75    }}
76}
77
78/// Macro for building EgValue's by leveraging the json::object! macro.
79///
80/// Panics if an attempt is made to build an EgValue::Blessed with
81/// an unknown class name or invalid field, however this should never
82/// happen in practice, since EgValue::Blessed's are validated well
83/// before they can be included in an eg::hash! {} invocation.
84///
85/// let a = eg::array! ["hello", "errbody"];
86#[macro_export]
87macro_rules! array {
88    ($($tts:tt)*) => {
89        match $crate::EgValue::from_json_value(json::array!($($tts)*)) {
90            Ok(v) => v,
91            Err(e) => {
92                // Unlikely to get here, but not impossible.
93                let msg = format!("eg::hash! {e}");
94                log::error!("{msg}");
95                panic!("{}", msg);
96            }
97        }
98    }
99}
100
101#[test]
102fn macros() {
103    let v = eg::hash! {
104        "hello": "stuff",
105        "gbye": ["floogle", EgValue::new_object()]
106    };
107
108    assert_eq!(v["hello"].as_str(), Some("stuff"));
109    assert_eq!((eg::array![1, 2, 3]).len(), 3);
110}
111
112/// An JSON-ish object whose structure is defined in the IDL.
113#[derive(Debug, PartialEq, Clone)]
114pub struct BlessedValue {
115    idl_class: Arc<idl::Class>,
116    values: HashMap<String, EgValue>,
117}
118
119impl BlessedValue {
120    pub fn idl_class(&self) -> &Arc<idl::Class> {
121        &self.idl_class
122    }
123    pub fn values(&self) -> &HashMap<String, EgValue> {
124        &self.values
125    }
126}
127
128/// Wrapper class which stores JSON-style values with one special
129/// value type which maps to IDL objects.
130#[derive(Debug, PartialEq, Clone)]
131pub enum EgValue {
132    Null,
133    Number(json::number::Number),
134    Boolean(bool),
135    String(String),
136    Array(Vec<EgValue>),
137    Hash(HashMap<String, EgValue>),
138    Blessed(BlessedValue),
139}
140
141impl EgValue {
142    /// Parse a JSON string and turn it into an EgValue
143    ///
144    /// ```
145    /// use evergreen::EgValue;
146    /// let v = EgValue::parse("{\"id\":123}").expect("Parse OK");
147    /// assert!(v.id().is_ok());
148    /// if let EgValue::Hash(h) = v {
149    ///     assert!(h.get("id").is_some());
150    ///     assert!(h.get("id").unwrap().is_number());
151    /// } else {
152    ///     panic!("Should Be Object");
153    /// }
154    /// ```
155    pub fn parse(s: &str) -> EgResult<EgValue> {
156        match json::parse(s) {
157            Ok(v) => EgValue::from_json_value(v),
158            Err(e) => Err(format!("JSON Parse Error: {e} : {s}").into()),
159        }
160    }
161
162    /// Create a new empty blessed value using the provided class name.
163    pub fn stub(classname: &str) -> EgResult<EgValue> {
164        let idl_class = idl::get_class(classname)?.clone();
165        Ok(EgValue::Blessed(BlessedValue {
166            idl_class: idl_class.clone(),
167            values: HashMap::new(),
168        }))
169    }
170
171    /// Create a new blessed value from an existing Hash value using
172    /// the provided class name.
173    pub fn create(classname: &str, mut v: EgValue) -> EgResult<EgValue> {
174        v.bless(classname)?;
175        Ok(v)
176    }
177
178    /// Translate an EgValue::Hash into an EGValue::Blessed, non-recursively,
179    /// using the provided class name.
180    ///
181    /// Returns Err of the classname is unknown or the object
182    /// contains fields which are not in the IDL.
183    ///
184    /// Having all IDL fields is not required.
185    pub fn bless(&mut self, classname: &str) -> EgResult<()> {
186        let idl_class = idl::get_class(classname)?;
187
188        // Pull the map out of the EgValue::Hash so we can inspect
189        // it and eventually consume it.
190        let map = match self {
191            Self::Hash(ref mut h) => std::mem::take(h),
192            _ => return Err("Only EgValue::Hash's can be blessed".into()),
193        };
194
195        // Verify the existing data contains only fields that are
196        // represented in the IDL for the provided class.
197        for k in map.keys() {
198            if !idl_class.has_field(k) {
199                let msg = format!("IDL class '{classname}' has no field named '{k}'");
200                log::error!("{msg}");
201                return Err(msg.into());
202            }
203        }
204
205        // Transmute ourselves into a Blessed value and absorb the
206        // existing hashmap.
207        *self = EgValue::Blessed(BlessedValue {
208            idl_class: idl_class.clone(),
209            values: map,
210        });
211
212        Ok(())
213    }
214
215    /// Translates a Blessed value into a generic Hash value, non-recursively.
216    ///
217    /// Fields which are not represented in the Blessed value, but do
218    /// exist in the class definition for the value, are included in the
219    /// generated Hash as Null values.
220    ///
221    /// NO-OP for non-Blessed values.
222    pub fn unbless(&mut self) {
223        let (idl_class, mut map) = match self {
224            Self::Blessed(ref mut o) => (&o.idl_class, std::mem::take(&mut o.values)),
225            _ => return,
226        };
227
228        // Null's are not stored in Blessed values by default, but we do
229        // want all of the real fields to be present in the plain Hash that's
230        // generated from this method call, including NULL values.
231        for field in idl_class.real_fields() {
232            if !map.contains_key(field.name()) {
233                map.insert(field.name().to_string(), Self::Null);
234            }
235        }
236
237        // Add the _classname entry
238        map.insert(
239            HASH_CLASSNAME_KEY.to_string(),
240            EgValue::from(idl_class.classname()),
241        );
242
243        *self = EgValue::Hash(map);
244    }
245
246    /// Translates Blessed values into generic Hash values, recursively,
247    /// retaining the original classname in the HASH_CLASSNAME_KEY key.
248    ///
249    /// Fields which are not represented in the Blessed value, but do
250    /// exist in the class definition for the value, are included in the
251    /// generated Hash as Null values.
252    pub fn to_classed_hash(&mut self) {
253        let (idl_class, mut map) = match self {
254            Self::Array(ref mut list) => {
255                list.iter_mut().for_each(|v| v.to_classed_hash());
256                return;
257            }
258            Self::Hash(ref mut h) => {
259                h.values_mut().for_each(|v| v.to_classed_hash());
260                return;
261            }
262            Self::Blessed(ref mut o) => (&o.idl_class, std::mem::take(&mut o.values)),
263            _ => return,
264        };
265
266        map.values_mut().for_each(|v| v.to_classed_hash());
267
268        // Null's are not stored in Blessed values by default, but we do
269        // want all of the real fields to be present in the plain Hash that's
270        // generated from this method call, including NULL values.
271        for field in idl_class.real_fields() {
272            if !map.contains_key(field.name()) {
273                map.insert(field.name().to_string(), Self::Null);
274            }
275        }
276
277        // Add the _classname entry
278        map.insert(
279            HASH_CLASSNAME_KEY.to_string(),
280            EgValue::from(idl_class.classname()),
281        );
282
283        *self = EgValue::Hash(map);
284    }
285
286    /// Translate a raw JsonValue, which may contain class name keys
287    /// in the HASH_CLASSNAME_KEY field, into an EgValue.
288    pub fn from_classed_json_hash(v: JsonValue) -> EgResult<EgValue> {
289        let mut value = EgValue::from_json_value(v)?;
290        value.from_classed_hash()?;
291        Ok(value)
292    }
293
294    /// Translate Hash values containing class names in the HASH_CLASSNAME_KEY
295    /// into Blessed values, recursively.
296    pub fn from_classed_hash(&mut self) -> EgResult<()> {
297        if self.is_scalar() || self.is_blessed() {
298            return Ok(());
299        }
300
301        if let Self::Array(ref mut list) = self {
302            for val in list.iter_mut() {
303                val.from_classed_hash()?;
304            }
305            return Ok(());
306        }
307
308        // Only option left is Self::Hash
309
310        let classname = match self[HASH_CLASSNAME_KEY].as_str() {
311            Some(c) => c,
312            None => {
313                // Vanilla, un-classed hash
314                if let Self::Hash(ref mut m) = self {
315                    for v in m.values_mut() {
316                        v.from_classed_hash()?;
317                    }
318                }
319                return Ok(());
320            }
321        };
322
323        // This hash has class
324        let idl_class = idl::get_class(classname)?.clone();
325
326        let mut map = match self {
327            Self::Hash(ref mut m) => std::mem::take(m),
328            _ => return Ok(()), // can't get here
329        };
330
331        for (key, value) in map.iter_mut() {
332            if key == HASH_CLASSNAME_KEY {
333                // Skip _classname field.
334                continue;
335            }
336            if !idl_class.has_field(key) {
337                return Err(format!(
338                    "Class '{}' has no field named '{key}'",
339                    idl_class.classname()
340                )
341                .into());
342            }
343
344            value.from_classed_hash()?;
345        }
346
347        *self = EgValue::Blessed(BlessedValue {
348            idl_class,
349            values: map,
350        });
351
352        Ok(())
353    }
354
355    /// Remove NULL values from EgValue::Hash's contained within
356    /// EgValue::Hash's or EgValue::Array's
357    ///
358    /// Does not remove NULL Array values, since that would change value
359    /// positions, but may modify a hash/object which is a member of an
360    /// array.
361    ///
362    /// ```
363    /// use evergreen::EgValue;
364    ///
365    /// let mut h = EgValue::new_object();
366    /// h["hello"] = EgValue::Null;
367    /// h["hello2"] = 1.into();
368    /// h["hello3"] = vec![EgValue::from(2), EgValue::Null].into();
369    ///
370    /// h.scrub_hash_nulls();
371    ///
372    /// assert!(!h.has_key("hello"));
373    /// assert!(h.has_key("hello2"));
374    ///
375    /// // Array NULLs are retained
376    /// assert_eq!(h["hello3"].len(), 2);
377    /// ```
378    pub fn scrub_hash_nulls(&mut self) {
379        if let EgValue::Hash(ref mut m) = self {
380            // Build a new map containg the scrubbed values and no
381            // NULLs then turn that into the map used by this EGValue.
382            let mut newmap = HashMap::new();
383
384            for (key, mut val) in m.drain() {
385                if val.is_array() || val.is_object() {
386                    val.scrub_hash_nulls();
387                }
388                if !val.is_null() {
389                    newmap.insert(key, val);
390                }
391            }
392
393            let _ = std::mem::replace(m, newmap);
394        } else if let EgValue::Array(ref mut list) = self {
395            for v in list.iter_mut() {
396                v.scrub_hash_nulls();
397            }
398        }
399    }
400
401    /// True if this value is an Array and it contains the provided item.
402    /// ```
403    /// use evergreen::EgValue;
404    /// let v = EgValue::from(vec!["yes".to_string(), "no".to_string()]);
405    /// assert!(v.contains("no"));
406    /// assert!(!v.contains("nope"));
407    /// ```
408    ///
409    pub fn contains(&self, item: impl PartialEq<EgValue>) -> bool {
410        match *self {
411            EgValue::Array(ref vec) => vec.iter().any(|member| item == *member),
412            _ => false,
413        }
414    }
415
416    /// Wrap a JSON object (obj) in {"__c":"classname", "__p": obj}
417    ///
418    /// ```
419    /// use evergreen::EgValue;
420    ///
421    /// let v = json::array! ["one", "two", "three"];
422    /// let v = EgValue::add_class_wrapper(v, "foo");
423    /// let v = EgValue::from_json_value_plain(v);
424    /// assert!(v.is_object());
425    /// assert_eq!(v["__c"].as_str(), Some("foo"));
426    /// assert_eq!(v["__p"][0].as_str(), Some("one"));
427    /// assert_eq!(EgValue::wrapped_classname(&v.into_json_value()), Some("foo"));
428    pub fn add_class_wrapper(val: JsonValue, class: &str) -> json::JsonValue {
429        let mut hash = json::JsonValue::new_object();
430
431        hash.insert(JSON_CLASS_KEY, class).expect("Is Object");
432        hash.insert(JSON_PAYLOAD_KEY, val).expect("Is Object");
433        hash
434    }
435
436    /// Un-package a value wrapped in class+payload object and return
437    /// the class name and wrapped object.
438    pub fn remove_class_wrapper(mut obj: JsonValue) -> Option<(String, JsonValue)> {
439        EgValue::wrapped_classname(&obj)
440            .map(|cname| cname.to_string())
441            .map(|cname| (cname, obj[JSON_PAYLOAD_KEY].take()))
442    }
443
444    /// Return the classname of the wrapped object if one exists.
445    ///
446    /// ```
447    /// use evergreen::EgValue;
448    ///
449    /// let h = json::object! {
450    ///   "__c": "yup",
451    ///   "__p": [1, 2, 3]
452    /// };
453    ///
454    /// assert_eq!(EgValue::wrapped_classname(&h), Some("yup"));
455    /// ```
456    pub fn wrapped_classname(obj: &JsonValue) -> Option<&str> {
457        if obj.is_object()
458            && obj.has_key(JSON_CLASS_KEY)
459            && obj.has_key(JSON_PAYLOAD_KEY)
460            && obj[JSON_CLASS_KEY].is_string()
461        {
462            obj[JSON_CLASS_KEY].as_str()
463        } else {
464            None
465        }
466    }
467
468    /// Returns the number of elements/entries contained in an EgValue
469    /// Array, Hash, or BlessedValue.
470    ///
471    ///
472    /// ```
473    /// use evergreen as eg;
474    /// use eg::EgValue;
475    ///
476    /// let v = evergreen::array! ["one", "two", "three"];
477    /// assert_eq!(v.len(), 3);
478    ///
479    /// let v = evergreen::hash! {"just":"some","stuff":["fooozle", "fazzle", "frizzle"]};
480    /// assert_eq!(v.len(), 2);
481    /// ```
482    pub fn len(&self) -> usize {
483        match self {
484            EgValue::Array(ref l) => l.len(),
485            EgValue::Hash(ref h) => h.len(),
486            EgValue::Blessed(ref b) => b.values.len(),
487            _ => 0,
488        }
489    }
490
491    pub fn new_object() -> EgValue {
492        EgValue::Hash(HashMap::new())
493    }
494
495    pub fn new_array() -> EgValue {
496        EgValue::Array(Vec::new())
497    }
498
499    /// Replace self with EgValue::Null and return what was previously
500    /// stored at self.
501    pub fn take(&mut self) -> EgValue {
502        std::mem::replace(self, EgValue::Null)
503    }
504
505    /// Returns an owned String if this value is a String or a Number.
506    ///
507    /// Implementation directly mimics
508    /// <https://docs.rs/json/latest/src/json/value/mod.rs.html#367-381>
509    ///
510    /// ```
511    /// use evergreen as eg;
512    /// use eg::EgValue;
513    ///
514    /// let mut v = EgValue::from("howdy");
515    /// let s = v.take_string().expect("Has String");
516    /// assert_eq!(s, "howdy");
517    /// assert!(v.is_null());
518    ///
519    /// let mut v = EgValue::from(17.88);
520    /// let s = v.take_string().expect("Has Stringifiable Number");
521    /// assert_eq!(s, "17.88");
522    /// assert!(v.is_null());
523    ///
524    /// let mut v = eg::array! [null, false];
525    /// let s = v.take_string();
526    /// assert!(s.is_none());
527    /// ```
528    pub fn take_string(&mut self) -> Option<String> {
529        let mut placeholder = Self::Null;
530
531        mem::swap(self, &mut placeholder);
532
533        if let Self::String(s) = placeholder {
534            return Some(s);
535        }
536
537        if let Self::Number(n) = placeholder {
538            return Some(format!("{n}"));
539        }
540
541        // Not a Self::String value.
542        mem::swap(self, &mut placeholder);
543
544        None
545    }
546
547    /// Returns the inner Vec of this value if it's an Array, None otherwise.
548    ///
549    /// Inner value is replaced with an empty Vec.
550    ///
551    /// # Examples
552    ///
553    ///```
554    /// use evergreen as eg;
555    /// use eg::EgValue;
556    ///
557    /// let mut v = EgValue::from(["hello", "everyone"].as_slice());
558    /// let l = v.take_vec().expect("Is Array");
559    ///
560    /// assert_eq!(l.len(), 2);
561    /// if let EgValue::Array(newl) = v {
562    ///     assert!(newl.is_empty());
563    /// } else {
564    ///     panic!("Something went wrong");
565    /// }
566    /// ```
567    pub fn take_vec(&mut self) -> Option<Vec<EgValue>> {
568        let mut placeholder = Self::Null;
569
570        mem::swap(self, &mut placeholder);
571
572        if let Self::Array(list) = placeholder {
573            *self = Self::Array(Vec::new());
574            Some(list)
575        } else {
576            // This is not an array.
577            // Put the original value back
578            mem::swap(self, &mut placeholder);
579            None
580        }
581    }
582
583    /// Turn a value into a JSON string.
584    pub fn dump(&self) -> String {
585        // into_json_value consumes the value, hence the clone().
586        self.clone().into_json_value().dump()
587    }
588
589    /// Turn a value into a pretty-printed JSON string using the
590    /// provided level of indentation.
591    pub fn pretty(&self, indent: u16) -> String {
592        self.clone().into_json_value().pretty(indent)
593    }
594
595    /// Push a value onto the end of an Array.
596    ///
597    /// Err if self is not an Array.
598    pub fn push(&mut self, v: impl Into<EgValue>) -> EgResult<()> {
599        if let EgValue::Array(ref mut list) = self {
600            list.push(v.into());
601            Ok(())
602        } else {
603            Err("push() requires an EgValue::Array".into())
604        }
605    }
606
607    /// Insert a new value into an object-typed value.  Returns Err
608    /// if this is not an object-typed value.
609    pub fn insert(&mut self, key: &str, value: impl Into<EgValue>) -> EgResult<()> {
610        match self {
611            EgValue::Hash(ref mut o) => o.insert(key.to_string(), value.into()),
612            EgValue::Blessed(ref mut o) => o.values.insert(key.to_string(), value.into()),
613            _ => return Err(format!("{self} Cannot call insert() on a non-object type").into()),
614        };
615
616        Ok(())
617    }
618
619    /// True if this is a Hash or Blessed value which contains the
620    /// provided key.
621    /// ```
622    /// use evergreen::EgValue;
623    /// let v = EgValue::parse("{\"id\":123}").expect("Parses");
624    /// assert!(v.has_key("id"));
625    /// assert!(!v.has_key("foo"));
626    /// ```
627    pub fn has_key(&self, key: &str) -> bool {
628        match self {
629            EgValue::Hash(ref o) => o.contains_key(key),
630            EgValue::Blessed(ref o) => o.values.contains_key(key),
631            _ => false,
632        }
633    }
634
635    /// Translates a JsonValue into an EgValue treating values which
636    /// appear to be IDL-classed values as vanilla JsonValue::Object's.
637    ///
638    /// Useful if you know the data you are working with does
639    /// not contain any IDL-classed content or you're interested
640    /// in the parts of the message that may be Blessed.
641    pub fn from_json_value_plain(mut v: JsonValue) -> EgValue {
642        match v {
643            JsonValue::Null => EgValue::Null,
644            JsonValue::Boolean(b) => EgValue::Boolean(b),
645            JsonValue::Short(_) | JsonValue::String(_) => EgValue::String(v.take_string().unwrap()),
646            JsonValue::Number(n) => EgValue::Number(n),
647            JsonValue::Array(mut list) => {
648                let mut val_list = Vec::new();
649                for v in list.drain(..) {
650                    val_list.push(EgValue::from_json_value_plain(v));
651                }
652                EgValue::Array(val_list)
653            }
654            JsonValue::Object(_) => {
655                let mut map = HashMap::new();
656                let mut keys: Vec<String> = v.entries().map(|(k, _)| k.to_string()).collect();
657
658                while let Some(k) = keys.pop() {
659                    let val = EgValue::from_json_value_plain(v.remove(&k));
660                    map.insert(k, val);
661                }
662                EgValue::Hash(map)
663            }
664        }
665    }
666
667    /// Transform a JSON value into an EgValue.
668    ///
669    /// Returns an Err if the value is shaped like and IDL object
670    /// but contains an unrecognized class name.
671    pub fn from_json_value(mut v: JsonValue) -> EgResult<EgValue> {
672        if v.is_number() || v.is_null() || v.is_boolean() || v.is_string() {
673            return Ok(EgValue::from_json_value_plain(v));
674        }
675
676        if let JsonValue::Array(mut list) = v {
677            let mut val_list = Vec::new();
678            for v in list.drain(..) {
679                val_list.push(EgValue::from_json_value(v)?);
680            }
681            return Ok(EgValue::Array(val_list));
682        }
683
684        // JSON object
685        let mut map = HashMap::new();
686        let mut keys: Vec<String> = v.entries().map(|(k, _)| k.to_string()).collect();
687
688        if EgValue::wrapped_classname(&v).is_none() {
689            // Vanilla JSON object
690            while let Some(k) = keys.pop() {
691                let val = EgValue::from_json_value(v.remove(&k))?;
692                map.insert(k, val);
693            }
694
695            return Ok(EgValue::Hash(map));
696        }
697
698        let (classname, mut list) = EgValue::remove_class_wrapper(v).unwrap();
699
700        let idl_class = idl::get_class(&classname)?;
701
702        let mut map = HashMap::new();
703        for field in idl_class.fields().values() {
704            if list.len() > field.array_pos() {
705                // No point in storing NULL entries since blessed values
706                // have a known set of fields.
707                let val = list[field.array_pos()].take();
708
709                if !val.is_null() {
710                    map.insert(field.name().to_string(), EgValue::from_json_value(val)?);
711                }
712            }
713        }
714
715        Ok(EgValue::Blessed(BlessedValue {
716            idl_class: idl_class.clone(),
717            values: map,
718        }))
719    }
720
721    /// Turn an EgValue into a vanilla JsonValue consuming the EgValue.
722    ///
723    /// Blessed objects are serialized into IDL-classed Arrays
724    pub fn into_json_value(self) -> JsonValue {
725        match self {
726            EgValue::Null => JsonValue::Null,
727            EgValue::Boolean(v) => JsonValue::Boolean(v),
728            EgValue::String(v) => JsonValue::String(v),
729            EgValue::Number(v) => json::from(v),
730            EgValue::Array(mut list) => {
731                let mut list2 = Vec::new();
732                for v in list.drain(..) {
733                    list2.push(v.into_json_value());
734                }
735                json::from(list2)
736            }
737            EgValue::Hash(mut o) => {
738                let mut obj = json::object! {};
739                for (k, v) in o.drain() {
740                    obj[k] = v.into_json_value();
741                }
742                obj
743            }
744            EgValue::Blessed(mut o) => {
745                let fields = o.idl_class.fields();
746
747                // Translate the fields hash into a sorted array
748                let mut sorted = fields.values().collect::<Vec<&idl::Field>>();
749                sorted.sort_by_key(|f| f.array_pos());
750
751                let mut array = JsonValue::new_array();
752
753                for field in sorted {
754                    let v = match o.values.remove(field.name()) {
755                        Some(v) => v,
756                        None => eg::NULL,
757                    };
758
759                    array.push(v.into_json_value()).expect("Is Array");
760                }
761
762                Self::add_class_wrapper(array, o.idl_class.classname())
763            }
764        }
765    }
766
767    /// True if self is not a Hash, Blessed, or Array.
768    pub fn is_scalar(&self) -> bool {
769        self.is_number() || self.is_null() || self.is_boolean() || self.is_string()
770    }
771
772    pub fn is_null(&self) -> bool {
773        self == &EgValue::Null
774    }
775
776    pub fn is_number(&self) -> bool {
777        matches!(self, EgValue::Number(_))
778    }
779
780    /// True if this is a number or a string that is numeric.
781    ///
782    /// # Examples
783    ///
784    /// ```
785    /// use evergreen::value::EgValue;
786    /// assert!(EgValue::from(1).is_numeric());
787    /// assert!(EgValue::from("-12.99999").is_numeric());
788    /// assert!(!EgValue::from(true).is_numeric());
789    /// assert!(!EgValue::from(vec![1]).is_numeric());
790    /// ```
791    pub fn is_numeric(&self) -> bool {
792        self.as_i64().is_some() || self.as_f64().is_some()
793    }
794
795    pub fn is_string(&self) -> bool {
796        matches!(self, EgValue::String(_))
797    }
798
799    pub fn is_boolean(&self) -> bool {
800        matches!(self, EgValue::Boolean(_))
801    }
802
803    pub fn is_array(&self) -> bool {
804        matches!(self, EgValue::Array(_))
805    }
806
807    /// True if this is a vanilla object or a classed object.
808    pub fn is_object(&self) -> bool {
809        matches!(self, EgValue::Hash(_) | EgValue::Blessed(_))
810    }
811
812    pub fn is_hash(&self) -> bool {
813        matches!(self, &EgValue::Hash(_))
814    }
815
816    /// True if this is an IDL-classed object
817    pub fn is_blessed(&self) -> bool {
818        matches!(self, &EgValue::Blessed(_))
819    }
820
821    /// Returns the IDL class if this is a blessed object.
822    pub fn classname(&self) -> Option<&str> {
823        if let EgValue::Blessed(b) = self {
824            Some(b.idl_class.classname())
825        } else {
826            None
827        }
828    }
829
830    pub fn idl_class(&self) -> Option<&Arc<idl::Class>> {
831        if let Self::Blessed(b) = self {
832            Some(b.idl_class())
833        } else {
834            None
835        }
836    }
837
838    /// Same as JsonValue::is_empty()
839    ///
840    /// # Examples
841    ///
842    /// ```
843    /// use evergreen::value::EgValue;
844    /// assert!(EgValue::from("").is_empty());
845    /// assert!(!EgValue::from(" ").is_empty());
846    /// ```
847    pub fn is_empty(&self) -> bool {
848        match self {
849            Self::Number(n) => *n == 0,
850            Self::String(ref s) => s.is_empty(),
851            Self::Boolean(b) => !b,
852            Self::Null => true,
853            Self::Array(ref l) => l.is_empty(),
854            Self::Hash(ref h) => h.is_empty(),
855            Self::Blessed(ref h) => h.values.is_empty(),
856        }
857    }
858
859    /// Variant of as_str() that produces an error if this value
860    /// is not a string.
861    ///
862    /// NOTE if the value may exist as a Number, consider .to_string()
863    /// instead, which will coerce numbers into strings.
864    pub fn str(&self) -> EgResult<&str> {
865        self.as_str()
866            .ok_or_else(|| format!("{self} is not a string").into())
867    }
868
869    pub fn as_str(&self) -> Option<&str> {
870        if let EgValue::String(s) = self {
871            Some(s.as_str())
872        } else {
873            None
874        }
875    }
876
877    /// Translates String and Number values into allocated strings.
878    ///
879    /// None if the value is neither a Number or String.
880    ///
881    /// # Examples
882    ///
883    /// ```
884    /// use evergreen::value::EgValue;
885    /// assert_eq!(EgValue::from("abc").to_string().as_deref(), Some("abc"));
886    /// assert_eq!(EgValue::from(true).to_string(), None);
887    /// ```
888    pub fn to_string(&self) -> Option<String> {
889        match self {
890            EgValue::String(s) => Some(s.to_string()),
891            EgValue::Number(n) => Some(format!("{n}")),
892            _ => None,
893        }
894    }
895
896    /// Translates String and Number values into allocated strings.
897    ///
898    /// Err if self cannot be stringified.
899    pub fn string(&self) -> EgResult<String> {
900        self.to_string()
901            .ok_or_else(|| format!("{self} cannot be stringified").into())
902    }
903
904    pub fn as_int(&self) -> Option<i64> {
905        self.as_i64()
906    }
907
908    /// Variant of EgValue::as_int() that produces an Err self cannot be
909    /// turned into an int
910    pub fn int(&self) -> EgResult<i64> {
911        self.as_int()
912            .ok_or_else(|| format!("{self} is not an integer").into())
913    }
914
915    /// Useful for panicing if a value cannot be coerced into an int,
916    /// particularly within iterator filters, etc.
917    pub fn int_required(&self) -> i64 {
918        self.int().expect("No int found")
919    }
920
921    pub fn as_i64(&self) -> Option<i64> {
922        match self {
923            EgValue::Number(n) => (*n).try_into().ok(),
924            // It's not uncommon to receive numeric strings over the wire.
925            EgValue::String(ref s) => s.parse::<i64>().ok(),
926            _ => None,
927        }
928    }
929
930    pub fn as_u64(&self) -> Option<u64> {
931        match self {
932            EgValue::Number(n) => (*n).try_into().ok(),
933            // It's not uncommon to receive numeric strings over the wire.
934            EgValue::String(ref s) => s.parse::<u64>().ok(),
935            _ => None,
936        }
937    }
938
939    pub fn as_usize(&self) -> Option<usize> {
940        match self {
941            EgValue::Number(n) => (*n).try_into().ok(),
942            // It's not uncommon to receive numeric strings over the wire.
943            EgValue::String(ref s) => s.parse::<usize>().ok(),
944            _ => None,
945        }
946    }
947
948    pub fn as_isize(&self) -> Option<isize> {
949        match self {
950            EgValue::Number(n) => (*n).try_into().ok(),
951            // It's not uncommon to receive numeric strings over the wire.
952            EgValue::String(ref s) => s.parse::<isize>().ok(),
953            _ => None,
954        }
955    }
956
957    pub fn as_u16(&self) -> Option<u16> {
958        match self {
959            EgValue::Number(n) => (*n).try_into().ok(),
960            // It's not uncommon to receive numeric strings over the wire.
961            EgValue::String(ref s) => s.parse::<u16>().ok(),
962            _ => None,
963        }
964    }
965
966    pub fn as_i16(&self) -> Option<i16> {
967        match self {
968            EgValue::Number(n) => (*n).try_into().ok(),
969            // It's not uncommon to receive numeric strings over the wire.
970            EgValue::String(ref s) => s.parse::<i16>().ok(),
971            _ => None,
972        }
973    }
974
975    pub fn as_f64(&self) -> Option<f64> {
976        match self {
977            EgValue::Number(n) => Some((*n).into()),
978            EgValue::String(ref s) => s.parse::<f64>().ok(),
979            _ => None,
980        }
981    }
982
983    /// Variant of EgValue::as_float() that produces an Err if no float
984    /// value is found.
985    pub fn float(&self) -> EgResult<f64> {
986        self.as_float()
987            .ok_or_else(|| format!("{self} is not a float").into())
988    }
989
990    /// Returns a float if we can be coerced into one.
991    pub fn as_float(&self) -> Option<f64> {
992        self.as_f64()
993    }
994
995    /// Returns a bool if we are a boolean value.
996    pub fn as_bool(&self) -> Option<bool> {
997        match self {
998            EgValue::Boolean(b) => Some(*b),
999            _ => None,
1000        }
1001    }
1002
1003    /// True if this EgValue is scalar and its value is true-ish.
1004    ///
1005    /// Zeros, empty strings, and strings that start with "f" are false
1006    /// since that's how false values are conveyed by the DB layer.
1007    pub fn boolish(&self) -> bool {
1008        match self {
1009            EgValue::Boolean(b) => *b,
1010            EgValue::Number(n) => *n != 0,
1011            EgValue::String(ref s) => !s.is_empty() && !s.starts_with('f'),
1012            _ => false,
1013        }
1014    }
1015
1016    /// Returns the numeric ID of this EgValue.
1017    ///
1018    /// Must be a Hash or Blessed with an "id" field and a numeric value.
1019    pub fn id(&self) -> EgResult<i64> {
1020        // If it's Blessed, verify "id" is a valid field so
1021        // the index lookup doesn't panic.
1022        if let EgValue::Blessed(ref o) = self {
1023            if o.idl_class().has_field("id") {
1024                self["id"]
1025                    .as_i64()
1026                    .ok_or_else(|| format!("{self} has no valid ID"))?;
1027            }
1028        }
1029        self["id"]
1030            .as_i64()
1031            .ok_or_else(|| format!("{self} has no valid ID").into())
1032    }
1033
1034    /// Returns the idl::Field for the primary key if present.
1035    pub fn pkey_field(&self) -> Option<&idl::Field> {
1036        if let EgValue::Blessed(b) = self {
1037            b.idl_class.pkey_field()
1038        } else {
1039            None
1040        }
1041    }
1042
1043    /// Returns the value from the primary key field.
1044    ///
1045    /// Returns None if the value has no primary key field.
1046    pub fn pkey_value(&self) -> Option<&EgValue> {
1047        if let Some(pkey_field) = self.pkey_field() {
1048            Some(&self[pkey_field.name()])
1049        } else {
1050            None
1051        }
1052    }
1053
1054    pub fn pkey_info(&self) -> Option<(&idl::Field, &EgValue)> {
1055        if let Some(f) = self.pkey_field() {
1056            if let Some(v) = self.pkey_value() {
1057                return Some((f, v));
1058            }
1059        }
1060        None
1061    }
1062
1063    /// Value stored in the reporter:selector field if set.
1064    pub fn selector_value(&self) -> Option<&EgValue> {
1065        if let EgValue::Blessed(b) = self {
1066            if let Some(selector) = b.idl_class.selector() {
1067                return Some(&self[selector]);
1068            }
1069        }
1070
1071        None
1072    }
1073
1074    pub fn pop(&mut self) -> EgValue {
1075        if let Self::Array(ref mut list) = self {
1076            list.pop().unwrap_or(eg::NULL)
1077        } else {
1078            eg::NULL
1079        }
1080    }
1081
1082    /// Remove and return the value found at the specified index.
1083    ///
1084    /// If the index is not present or self is not an Array,
1085    /// returns EgValue::Null.
1086    pub fn array_remove(&mut self, index: usize) -> EgValue {
1087        if let Self::Array(ref mut list) = self {
1088            if list.len() > index {
1089                return list.remove(index);
1090            }
1091        }
1092        eg::NULL
1093    }
1094
1095    /// Remove a value from an object-like thing and, if found, return
1096    /// the value to the caller.
1097    pub fn remove(&mut self, key: &str) -> Option<EgValue> {
1098        if let Self::Hash(ref mut map) = self {
1099            map.remove(key)
1100        } else if let Self::Blessed(ref mut o) = self {
1101            o.values.remove(key)
1102        } else {
1103            None
1104        }
1105    }
1106
1107    /// Iterator over values in an EgValue::Array.
1108    ///
1109    /// Returns an empty iterator if this is not an EgValue::Array type.
1110    pub fn members(&self) -> impl Iterator<Item = &EgValue> {
1111        match *self {
1112            EgValue::Array(ref list) => list.iter(),
1113            _ => [].iter(),
1114        }
1115    }
1116
1117    /// Mutable Iterator over values in an EgValue::Array.
1118    ///
1119    /// Returns an empty iterator if this is not an EgValue::Array type.
1120    pub fn members_mut(&mut self) -> impl Iterator<Item = &mut EgValue> {
1121        match *self {
1122            EgValue::Array(ref mut list) => list.iter_mut(),
1123            _ => [].iter_mut(),
1124        }
1125    }
1126
1127    /// Iterator over key-value pairs of an EgValue::{Object, Blessed}
1128    ///
1129    /// Returns an empty iterator if this is not an Object or Blessed type.
1130    pub fn entries(&self) -> EgValueEntries {
1131        EgValueEntries {
1132            map_iter: match self {
1133                EgValue::Hash(ref o) => Some(o.iter()),
1134                EgValue::Blessed(ref o) => Some(o.values.iter()),
1135                _ => None,
1136            },
1137        }
1138    }
1139
1140    /// Mutable Iterator over key-value pairs of an EgValue::{Object, Blessed}
1141    ///
1142    /// Returns an empty iterator if this is not an Object or Blessed type.
1143    pub fn entries_mut(&mut self) -> EgValueEntriesMut {
1144        EgValueEntriesMut {
1145            map_iter: match self {
1146                EgValue::Hash(ref mut o) => Some(o.iter_mut()),
1147                EgValue::Blessed(ref mut o) => Some(o.values.iter_mut()),
1148                _ => None,
1149            },
1150        }
1151    }
1152
1153    /// Iterator over keys of an EgValue::{Object, Blessed} type.
1154    ///
1155    /// Returns an empty iterator if this is not an Object or Blessed type.
1156    pub fn keys(&self) -> EgValueKeys {
1157        EgValueKeys {
1158            map_iter: match self {
1159                EgValue::Hash(ref o) => Some(o.keys()),
1160                EgValue::Blessed(ref o) => Some(o.values.keys()),
1161                _ => None,
1162            },
1163        }
1164    }
1165
1166    /// De-Flesh a blessed object.
1167    ///
1168    /// Replace Object values with the primary key value for each fleshed field.
1169    /// Replace Array values with empty arrays.
1170    /// Ignore everything else.
1171    pub fn deflesh(&mut self) -> EgResult<()> {
1172        let inner = match self {
1173            EgValue::Blessed(ref mut i) => i,
1174            _ => return Ok(()),
1175        };
1176
1177        // This alternate idl_class access allows us to modify ourselves
1178        // in the loop below w/o a parallel borrow
1179        let idl_class = inner.idl_class.clone();
1180
1181        for (name, field) in idl_class.fields().iter() {
1182            if self[name].is_array() {
1183                self[name] = EgValue::new_array();
1184                continue;
1185            }
1186
1187            if !self[name].is_blessed() {
1188                continue;
1189            }
1190
1191            if field.is_virtual() {
1192                // Virtual fields can be fully cleared.
1193                self[name] = eg::NULL;
1194            } else if let Some(pval) = self[name].pkey_value() {
1195                self[name] = pval.clone();
1196            } else {
1197                self[name] = eg::NULL;
1198            }
1199        }
1200
1201        Ok(())
1202    }
1203
1204    /// List of real IDL fields for this blessed value.
1205    ///
1206    /// Empty iterator if this is not a blessed value.
1207    pub fn real_fields(&self) -> Vec<&idl::Field> {
1208        if let EgValue::Blessed(b) = self {
1209            b.idl_class().real_fields()
1210        } else {
1211            Vec::new()
1212        }
1213    }
1214
1215    /// List of real field sorted by field name.
1216    pub fn real_fields_sorted(&self) -> Vec<&idl::Field> {
1217        if let EgValue::Blessed(b) = self {
1218            b.idl_class().real_fields_sorted()
1219        } else {
1220            Vec::new()
1221        }
1222    }
1223
1224    /// True if self is a Blessed value and has the provided field
1225    /// by field name.
1226    pub fn has_real_field(&self, field: &str) -> bool {
1227        if let EgValue::Blessed(b) = self {
1228            b.idl_class().has_real_field(field)
1229        } else {
1230            false
1231        }
1232    }
1233}
1234
1235// EgValue Iterators ------------------------------------------------------
1236
1237// HashMap iterators are a little more complicated and required
1238// tracking the hashmap iterator within a custom iterator type.
1239
1240pub struct EgValueEntriesMut<'a> {
1241    map_iter: Option<std::collections::hash_map::IterMut<'a, String, EgValue>>,
1242}
1243
1244impl<'a> Iterator for EgValueEntriesMut<'a> {
1245    type Item = (&'a str, &'a mut EgValue);
1246
1247    fn next(&mut self) -> Option<Self::Item> {
1248        if let Some(iter) = self.map_iter.as_mut() {
1249            iter.next().map(|(k, v)| (k.as_str(), v))
1250        } else {
1251            None
1252        }
1253    }
1254}
1255
1256pub struct EgValueEntries<'a> {
1257    map_iter: Option<std::collections::hash_map::Iter<'a, String, EgValue>>,
1258}
1259
1260impl<'a> Iterator for EgValueEntries<'a> {
1261    type Item = (&'a str, &'a EgValue);
1262
1263    fn next(&mut self) -> Option<Self::Item> {
1264        if let Some(iter) = self.map_iter.as_mut() {
1265            iter.next().map(|(k, v)| (k.as_str(), v))
1266        } else {
1267            None
1268        }
1269    }
1270}
1271
1272pub struct EgValueKeys<'a> {
1273    map_iter: Option<std::collections::hash_map::Keys<'a, String, EgValue>>,
1274}
1275
1276impl<'a> Iterator for EgValueKeys<'a> {
1277    type Item = &'a str;
1278
1279    fn next(&mut self) -> Option<Self::Item> {
1280        if let Some(iter) = self.map_iter.as_mut() {
1281            iter.next().map(|k| k.as_str())
1282        } else {
1283            None
1284        }
1285    }
1286}
1287
1288impl fmt::Display for EgValue {
1289    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1290        match self {
1291            EgValue::Null => write!(f, "null"),
1292            EgValue::Boolean(b) => write!(f, "{b}"),
1293            EgValue::String(ref s) => write!(f, "{s}"),
1294            EgValue::Number(n) => write!(f, "{n}"),
1295            EgValue::Array(_) => write!(f, "<array>"),
1296            EgValue::Hash(_) => write!(f, "<hash>"),
1297            EgValue::Blessed(ref o) => {
1298                let mut s = o.idl_class.classname().to_string();
1299                if let Some(pkey) = self.pkey_field() {
1300                    if let Some(pval) = self.pkey_value() {
1301                        s += &format!(" {}={pval}", pkey.name());
1302                    }
1303                }
1304                if let Some(selector) = self.selector_value() {
1305                    s += &format!(" label={selector}");
1306                }
1307                write!(f, "{s}")
1308            }
1309        }
1310    }
1311}
1312
1313impl PartialEq<EgValue> for &str {
1314    fn eq(&self, val: &EgValue) -> bool {
1315        if let Some(s) = val.as_str() {
1316            s == *self
1317        } else {
1318            false
1319        }
1320    }
1321}
1322
1323impl PartialEq<EgValue> for &String {
1324    fn eq(&self, val: &EgValue) -> bool {
1325        if let Some(s) = val.as_str() {
1326            s == self.as_str()
1327        } else {
1328            false
1329        }
1330    }
1331}
1332
1333impl PartialEq<EgValue> for String {
1334    fn eq(&self, val: &EgValue) -> bool {
1335        if let Some(s) = val.as_str() {
1336            s == self.as_str()
1337        } else {
1338            false
1339        }
1340    }
1341}
1342
1343impl PartialEq<EgValue> for i64 {
1344    fn eq(&self, val: &EgValue) -> bool {
1345        if let Some(v) = val.as_i64() {
1346            v == *self
1347        } else {
1348            false
1349        }
1350    }
1351}
1352
1353impl PartialEq<EgValue> for f64 {
1354    fn eq(&self, val: &EgValue) -> bool {
1355        if let Some(v) = val.as_f64() {
1356            v == *self
1357        } else {
1358            false
1359        }
1360    }
1361}
1362
1363impl PartialEq<EgValue> for bool {
1364    fn eq(&self, val: &EgValue) -> bool {
1365        if let Some(v) = val.as_bool() {
1366            v == *self
1367        } else {
1368            false
1369        }
1370    }
1371}
1372
1373impl From<EgValue> for JsonValue {
1374    fn from(v: EgValue) -> JsonValue {
1375        v.into_json_value()
1376    }
1377}
1378
1379impl TryFrom<JsonValue> for EgValue {
1380    type Error = EgError;
1381    fn try_from(v: JsonValue) -> EgResult<EgValue> {
1382        EgValue::from_json_value(v)
1383    }
1384}
1385
1386impl From<Option<&str>> for EgValue {
1387    fn from(v: Option<&str>) -> EgValue {
1388        match v {
1389            Some(v) => EgValue::from(v),
1390            None => EgValue::Null,
1391        }
1392    }
1393}
1394
1395impl From<Vec<i64>> for EgValue {
1396    fn from(mut v: Vec<i64>) -> EgValue {
1397        EgValue::Array(v.drain(..).map(EgValue::from).collect())
1398    }
1399}
1400
1401impl From<&[&str]> for EgValue {
1402    fn from(l: &[&str]) -> EgValue {
1403        EgValue::Array(l.iter().map(|v| EgValue::from(*v)).collect())
1404    }
1405}
1406
1407impl From<Vec<String>> for EgValue {
1408    fn from(mut v: Vec<String>) -> EgValue {
1409        EgValue::Array(v.drain(..).map(EgValue::from).collect())
1410    }
1411}
1412
1413impl From<u16> for EgValue {
1414    fn from(v: u16) -> EgValue {
1415        EgValue::Number(v.into())
1416    }
1417}
1418
1419impl From<bool> for EgValue {
1420    fn from(v: bool) -> EgValue {
1421        EgValue::Boolean(v)
1422    }
1423}
1424
1425impl From<Option<bool>> for EgValue {
1426    fn from(o: Option<bool>) -> EgValue {
1427        if let Some(b) = o {
1428            EgValue::from(b)
1429        } else {
1430            eg::NULL
1431        }
1432    }
1433}
1434
1435impl From<HashMap<std::string::String, Vec<i64>>> for EgValue {
1436    fn from(mut m: HashMap<std::string::String, Vec<i64>>) -> EgValue {
1437        let mut map: HashMap<String, EgValue> = HashMap::new();
1438        for (k, v) in m.drain() {
1439            map.insert(k, v.into());
1440        }
1441        EgValue::Hash(map)
1442    }
1443}
1444
1445impl From<Vec<EgValue>> for EgValue {
1446    fn from(v: Vec<EgValue>) -> EgValue {
1447        EgValue::Array(v)
1448    }
1449}
1450
1451impl From<&str> for EgValue {
1452    fn from(s: &str) -> EgValue {
1453        EgValue::String(s.to_string())
1454    }
1455}
1456
1457impl From<Option<String>> for EgValue {
1458    fn from(o: Option<String>) -> EgValue {
1459        if let Some(s) = o {
1460            EgValue::from(s)
1461        } else {
1462            eg::NULL
1463        }
1464    }
1465}
1466
1467impl From<String> for EgValue {
1468    fn from(s: String) -> EgValue {
1469        EgValue::String(s)
1470    }
1471}
1472
1473impl From<i32> for EgValue {
1474    fn from(s: i32) -> EgValue {
1475        EgValue::Number(s.into())
1476    }
1477}
1478
1479impl From<Option<i32>> for EgValue {
1480    fn from(v: Option<i32>) -> EgValue {
1481        if let Some(n) = v {
1482            EgValue::from(n)
1483        } else {
1484            eg::NULL
1485        }
1486    }
1487}
1488
1489impl From<i8> for EgValue {
1490    fn from(s: i8) -> EgValue {
1491        EgValue::Number(s.into())
1492    }
1493}
1494
1495impl From<i16> for EgValue {
1496    fn from(s: i16) -> EgValue {
1497        EgValue::Number(s.into())
1498    }
1499}
1500
1501impl From<Option<i16>> for EgValue {
1502    fn from(v: Option<i16>) -> EgValue {
1503        if let Some(n) = v {
1504            EgValue::from(n)
1505        } else {
1506            eg::NULL
1507        }
1508    }
1509}
1510
1511impl From<Option<i8>> for EgValue {
1512    fn from(v: Option<i8>) -> EgValue {
1513        if let Some(n) = v {
1514            EgValue::from(n)
1515        } else {
1516            eg::NULL
1517        }
1518    }
1519}
1520
1521impl From<i64> for EgValue {
1522    fn from(s: i64) -> EgValue {
1523        EgValue::Number(s.into())
1524    }
1525}
1526
1527impl From<&i64> for EgValue {
1528    fn from(s: &i64) -> EgValue {
1529        EgValue::Number((*s).into())
1530    }
1531}
1532
1533impl From<Option<i64>> for EgValue {
1534    fn from(v: Option<i64>) -> EgValue {
1535        if let Some(n) = v {
1536            EgValue::from(n)
1537        } else {
1538            eg::NULL
1539        }
1540    }
1541}
1542
1543impl From<f64> for EgValue {
1544    fn from(s: f64) -> EgValue {
1545        EgValue::Number(s.into())
1546    }
1547}
1548
1549impl From<Option<f64>> for EgValue {
1550    fn from(v: Option<f64>) -> EgValue {
1551        if let Some(n) = v {
1552            EgValue::from(n)
1553        } else {
1554            eg::NULL
1555        }
1556    }
1557}
1558
1559impl From<f32> for EgValue {
1560    fn from(s: f32) -> EgValue {
1561        EgValue::Number(s.into())
1562    }
1563}
1564
1565impl From<Option<f32>> for EgValue {
1566    fn from(v: Option<f32>) -> EgValue {
1567        if let Some(n) = v {
1568            EgValue::from(n)
1569        } else {
1570            eg::NULL
1571        }
1572    }
1573}
1574
1575impl From<u32> for EgValue {
1576    fn from(s: u32) -> EgValue {
1577        EgValue::Number(s.into())
1578    }
1579}
1580
1581impl From<u64> for EgValue {
1582    fn from(s: u64) -> EgValue {
1583        EgValue::Number(s.into())
1584    }
1585}
1586
1587impl From<u8> for EgValue {
1588    fn from(s: u8) -> EgValue {
1589        EgValue::Number(s.into())
1590    }
1591}
1592
1593impl From<usize> for EgValue {
1594    fn from(s: usize) -> EgValue {
1595        EgValue::Number(s.into())
1596    }
1597}
1598
1599impl TryFrom<(&str, EgValue)> for EgValue {
1600    type Error = EgError;
1601    fn try_from(parts: (&str, EgValue)) -> EgResult<EgValue> {
1602        EgValue::create(parts.0, parts.1)
1603    }
1604}
1605
1606/// Allows numeric index access to EgValue::Array's
1607impl Index<usize> for EgValue {
1608    type Output = EgValue;
1609
1610    /// Returns the EgValue stored in the provided index or EgValue::Null;
1611    fn index(&self, index: usize) -> &Self::Output {
1612        match self {
1613            Self::Array(ref o) => {
1614                if let Some(v) = o.get(index) {
1615                    v
1616                } else {
1617                    &eg::NULL
1618                }
1619            }
1620            _ => &eg::NULL,
1621        }
1622    }
1623}
1624
1625/// Allows mutable numeric access to EgValue::Array's.
1626///
1627/// Mutably acessing an index that is beyond the size of the list will
1628/// cause NULL values to be appended to the list until the list reaches
1629/// the needed size to allow editing the specified index.
1630impl IndexMut<usize> for EgValue {
1631    fn index_mut(&mut self, index: usize) -> &mut EgValue {
1632        if !self.is_array() {
1633            *self = EgValue::new_array();
1634        }
1635        if let EgValue::Array(ref mut list) = self {
1636            while list.len() < index + 1 {
1637                list.push(eg::NULL)
1638            }
1639            &mut list[index]
1640        } else {
1641            panic!("Cannot get here")
1642        }
1643    }
1644}
1645
1646/// Allows index-based access to EgValue Hash and Blessed values.
1647///
1648/// Follows the pattern of JsonValue where undefined values are all null's
1649impl Index<&str> for EgValue {
1650    type Output = EgValue;
1651
1652    /// Returns the EgValue stored in this EgValue at the
1653    /// specified index (field name).
1654    ///
1655    /// Panics if the IDL Class for this EgValue does not
1656    /// contain the named field.
1657    fn index(&self, key: &str) -> &Self::Output {
1658        match self {
1659            Self::Blessed(ref o) => {
1660                if key.starts_with('_') || o.idl_class.has_field(key) {
1661                    o.values.get(key).unwrap_or(&eg::NULL)
1662                } else {
1663                    let err = format!(
1664                        "Indexing IDL class '{}': No field named '{key}'",
1665                        self.classname().unwrap()
1666                    );
1667                    log::error!("{err}");
1668                    panic!("{}", err);
1669                }
1670            }
1671            EgValue::Hash(ref hash) => hash.get(key).unwrap_or(&eg::NULL),
1672            // Only Object-y things can be indexed
1673            _ => &eg::NULL,
1674        }
1675    }
1676}
1677
1678/// DOCS
1679///
1680/// ```
1681/// use evergreen::value::EgValue;
1682/// let mut v = EgValue::String("hello".to_string());
1683/// v["blarg"] = EgValue::String("b".to_string());
1684/// assert_eq!(v["blarg"], EgValue::String("b".to_string()));
1685/// ```
1686impl IndexMut<&str> for EgValue {
1687    fn index_mut(&mut self, key: &str) -> &mut Self::Output {
1688        let (is_classed, has_field) = match self {
1689            Self::Blessed(o) => (true, o.idl_class.has_field(key)),
1690            _ => (false, false),
1691        };
1692
1693        if is_classed {
1694            if !has_field || key.starts_with('_') {
1695                let err = format!(
1696                    "Indexing IDL class '{}': No field named '{key}'",
1697                    self.classname().unwrap()
1698                );
1699                log::error!("{err}");
1700                panic!("{}", err);
1701            }
1702
1703            if let Self::Blessed(ref mut o) = self {
1704                if !o.values.contains_key(key) {
1705                    o.values.insert(key.to_string(), eg::NULL);
1706                }
1707
1708                o.values.get_mut(key).unwrap()
1709            } else {
1710                panic!("Cannot get here");
1711            }
1712        } else {
1713            if let EgValue::Hash(ref mut hash) = self {
1714                if hash.get(key).is_none() {
1715                    hash.insert(key.to_string(), eg::NULL);
1716                }
1717                return hash.get_mut(key).unwrap();
1718            }
1719
1720            // Indexing into a non-object turns it into an object.
1721            let mut map = HashMap::new();
1722            map.insert(key.to_string(), eg::NULL);
1723            *self = EgValue::Hash(map);
1724            &mut self[key]
1725        }
1726    }
1727}
1728
1729impl Index<&String> for EgValue {
1730    type Output = EgValue;
1731    fn index(&self, key: &String) -> &Self::Output {
1732        &self[key.as_str()]
1733    }
1734}
1735
1736impl IndexMut<&String> for EgValue {
1737    fn index_mut(&mut self, key: &String) -> &mut Self::Output {
1738        &mut self[key.as_str()]
1739    }
1740}