5

I have a source JSON with several keys and values and I'd like to take several target JSONs and check if they are a subset of that JSON: all fields in target JSON are present in source JSON and hold the same values.

To accomplish this, I'd like to place several values of different types in the value part of a HashMap and call equals on those values.

There are several types of values in the map and I'd like to accept some key-value pair and check if

  1. the key is in the map
  2. the value is the same as the value in the map.

This is an example of what I'd like to do in Java:

boolean isInMap(Map<String, Object> map, String key, Object value) {
    return map.containsKey(key) && map.get(key).equals(value);
}

This might be an XY question but how can I do this in Rust?

blap_bleep
  • 51
  • 4
  • 1
    Have you had a look at what an [idiomatic JSON type](https://docs.serde.rs/serde_json/value/enum.Value.html) would be in Rust? There is no need to use `Object` here, you would just use `Value`. – mcarton Jan 13 '18 at 16:42
  • Related: [How do I create a heterogeneous collection of objects?](https://stackoverflow.com/q/27957103/155423); [How to test for equality between trait objects?](https://stackoverflow.com/q/25339603/155423) – Shepmaster Jan 13 '18 at 17:02
  • 2
    *It's pretty much what @mcarton referred to in the serde JSON library* — why not just *use* `serde_json::Value`? Why create your own? – Shepmaster Jan 20 '18 at 01:39
  • @Shepmaster two reasons. One, I needed to support less types than what was provided in `serde`. Second, I am trying out rust so I wanted to actually solve this on my own. – blap_bleep Jan 21 '18 at 06:19

1 Answers1

0

It's pretty much what @mcarton referred to in the Serde JSON library, only I used a enum match, which I'm not sure is better.

enum Value {
    Str(String),
    Int(i32),
    // other value types
}

impl PartialEq for Value {
    fn eq(&self, other: &Value) -> bool {
        match *self {
            Value::Str(ref s1) => match *other {
                Value::Str(ref s2) => s1 == s2,
                _ => false
            },
            Value::Int(i1) => match *other {
                Value::Int(i2) => i1 == i2,
                _ => false
            },
            // other implementations
        }
    }
}

Since I needed to support less types than what was provided in Serde and I am trying out Rust, I created my own enum instead of using serde_json::Value

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
blap_bleep
  • 51
  • 4
  • 2
    Normally, such a match would be [written on the tuple of values](https://play.rust-lang.org/?gist=5c2ee66415b0409a2fe19a0c6d887f8c&version=stable). In this specific case, you can [just `#[derive(PartialEq)]` for your type](https://play.rust-lang.org/?gist=e0fdfd70a0e1add5d55d984e55f5ebad&version=stable). – Shepmaster Jan 21 '18 at 14:39
  • @Shepmaster awesome! I didn't know you could `#[derive(PartialEq)]` on enums, looking at the code in the playground it seems to be doing the same thing (~20 lines difference between them), does`#[derive(PartialEq)]` on enums compile down to `match`es? Also, in pattern matching is the correct match arm statically linked in compilation or is it a runtime check? – blap_bleep Jan 21 '18 at 18:44
  • 2
    In the general case, it *has* to be a runtime check. The variable could be coming from outside of the source code, after all. I'm sure the optimizer eliminates certain constant cases though. There are [tools that let you see exactly what it would expand to](https://stackoverflow.com/a/37639012/155423). – Shepmaster Jan 21 '18 at 18:50