Implement Trait for Enum

I am new to Rust, and trying to process some JSON data from a Nodejs server, but cannot figure out this error:

the trait std::convert::From<Rand> is not implemented for json::value::JsonValue

help: the following implementations were found:
<json::value::JsonValue as std::convert::From<&'a [T]>>
<json::value::JsonValue as std::convert::From<&'a str>>
<json::value::JsonValue as std::convert::From>
<json::value::JsonValue as std::convert::From>
and 18 others
note: required because of the requirements on the impl of std::convert::Into<json::value::JsonValue> for Randrustc(E0277)
lib.rs(43, 12): the trait std::convert::From<Rand> is not implemented for json::value::JsonValue

Here is my code, including some of my commented out attempts at resolving the error:

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use wasm_bindgen::prelude::*;
// use wasm_bindgen::convert::traits::IntoWasmAbi;
// use JsonValue::object;
use json;

#[derive(Serialize, Deserialize)]
struct Rand {
    value: f32,
    date: String,
}

// enum JsonValue {
//     Rand(std::convert::From<Rand>),
// }
// impl std::convert::from<Rand> for json::JsonValue {
//     fn Rand(&self, f: &mut Rand) -> Rand::Result {
//         match self {
//             &json::JsonValue::Rand{
//                 ref Rand
//             } => {
//                 write!(f, "{{solution_type: {},}}",Rand)
//             }
//             _ => println!("Failed")
//         }
//     }
// }

#[wasm_bindgen]
pub fn get_max(rand_times: &str) -> String {
    // Loop through all json data, and find max
    let data: HashMap<String, String> = serde_json::from_str(rand_times).unwrap();
    let mut record = Rand {value: 0.0, date: "".to_string()};
    // let mut record: Rand = json::object!{value: 0.0, date: "".to_string()};

    for (k, v) in &data {
        let v_int: f32 = v.parse().unwrap();
        if &v_int > &record.value {
            record = Rand { value: v_int, date: k.to_string() };
        }
    }
    return json::stringify(record);
}

Any help is appreciated, including criticism of my methods.

For just fixing the error, try serde_json::to_string(&record).unwrap() instead of json::stringify(record).

1 Like

Thank you, for providing this. I would still like to find out how to resolve such an error. Essentially, understanding what it is saying.

Sure. In Rust we have the trait From in the standard library and its companion Into.

For two types A and B you can write the constraint A: From<B> or B: Into<A> both of which mean mostly the same, i.e. “B can be converted into A”. Now what this “can be converted” means is not 100% clear and basically the authors of the types A and/or B decide what it should mean, but it usually is a pretty canonical conversion, and almost one that can’t fail.

Now the function json::stringify takes an argument of any type T that can be converted in to JsonValue. (Read it’s signature here, see the T: Into<JsonValue>). I suppose in this case it is to make the method more user friendly than if it would just accept the type json::JsonValue, in particular see here where you can find that the author of the json crate indeed provides a bunch of From implementations for simple things like numbers, strings, bools, and more concrete JSON types from the crate itself, and also for vectors, slices and Option.

I should’ve probably mentioned it earlier, the crate json does not provide any facilities to serialize your custom struct data structures or so, it just turns its abstract JsonData data type (basically an abstract syntax tree for JSON) into strings and vice versa. For serialization you have already found serde, it works together with a lot of format-specific crates (here’s a list), like serde_json to allow full serialization (and deserialization) in a single function call.

Anyways back towards the error message: The json crate doesn’t even know about your type Rand and you didn’t explicitly provide any trait implementation to convert Rand into json::JsonValue either, nor does your derive statement produce that kind of trait implementation, hence a Rand cannot be passed to json::stringify.

If you know about these traits, the error message

error[E0277]: the trait bound `json::value::JsonValue: std::convert::From<Rand>` is not satisfied
   --> src\main.rs:43:12
    |
43  |     return json::stringify(record);
    |            ^^^^^^^^^^^^^^^ the trait `std::convert::From<Rand>` is not implemented for `json::value::JsonValue`
    |
   ::: \....\json-0.12.4\src\lib.rs:253:49
    |
253 | pub fn stringify<T>(root: T) -> String where T: Into<JsonValue> {
    |                                                 --------------- required by this bound in `json::stringify`
    |
    = help: the following implementations were found:
              <json::value::JsonValue as std::convert::From<&'a [T]>>
              <json::value::JsonValue as std::convert::From<&'a str>>
              <json::value::JsonValue as std::convert::From<bool>>
              <json::value::JsonValue as std::convert::From<f32>>
            and 18 others
    = note: required because of the requirements on the impl of `std::convert::Into<json::value::JsonValue>` for `Rand`

is precisely stating that the type of stringify requires its argument to be convertable into JsonValue but Rand does not provide a way to do so.

1 Like

Here’s ← an alternative implementation of your function. Perhaps you can take away something from it. It should not mean that everything you did differently was bad. It avoids a few String allocations and uses a library function for finding the maximum. Also note that you don’t need an return statement in the last line of a function.

Thank you. It is useful to know about methods like .max_by_key. I am familiar with JavaScript, so I am still wrapping my head around all the new concepts like serialising. As for the alternative implementation, it does look much clearer. Unfortunately, I did forget to mention that the format of the incoming data is String : String. So the conversion to int is necessary.

Your explanation behind the error is immensely helpful. Cheers

I noticed this and thougth it was a bug. But that’s not too much of a change.

Edit: Wait.. conversion to int? I thought your comment was referring to the fact that your value was written like "2020-01-01": "123.45" with the number (being however a float not an integer) written as a string.

Mostly as a challenge for myself I tried getting rid of all the unwrap and I found itertools::process_results which I never saw before. Pretty useful. Here’s the code.

No, you are correct. I made a blunder; it should be converted to a float.

Thank you, for your time and code. There is still quite a bit of your final version that goes over my head, but it is useful to have.

I will not be able to use it, as I am unsure how to make use of the error handling seeing as the function is being called within a Nodejs app. However, it is just a first project of mine, and I am using a small, perfect dataset.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.