1

I have a JSON object which represents some loose configuration. I'd like to provide functionality over "views" of the data based on some runtime conditions rather than working with the data directly.

In some cases, I still need to work with the "raw" data so I don't want to hold copies and multiple parsings of the same stuff.

As an example I have a baby JSON like this:

[
 {
  "type" : "banner",
  "text" : "some text",
 },
 {
  "type" : "toolbar",
  "text" : "some text",
  "color" : "#00FF00",
  "texture" : "border",
  "shadow" : "#000000"
 }
]

I am parsing the data to an object tree similar to this one:

use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Data {
    values: Vec<Message>,
}

#[derive(Serialize, Deserialize, Debug, Clone)]
struct Message {
    message_type: MessageType,
    text: String,
    additional_fields: HashMap<String, Value>,
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
enum MessageType {
    Banner,
    Toolbar,
}

// I have some helper functions to find things in the JSON
impl Data {
    pub fn get_message_of_type(&self, message_type: MessageType) -> Option<&Message> {
        self.values.iter().find(|x| x.message_type == message_type)
    }
}

Link to playground

I'd like a way to return a more ergonomic representation over the data relevant to the MessageType.

For instance, when the message is a toolbar it also has a "color" property among other properties.

I'd like to define a trait (or something else?) for Toolbar and "cast" the Message (or return some proxy to it) to assist in working with the very loose Message type.

Here is a contrived example

// some trait describing toolbar things
trait Toolbar {
    fn text() -> String;
    fn color() -> String;
    fn something_only_toolbar_relevant();
}

// NOT FUNCTIONING! This is what I am trying to figure out
impl Toolbar for Message
where
    message_type = "toolbar"
{
    fn text() -> String {
        self.text
    }
    fn color() -> String {
        let color = self.additional_fields.get("color");
        self.additional_fields.get("color").unwrap.as_str()
    }
}

// extend the Data class to return "toolbars"
// DOES NOT WORK!!! I am asking how to do this
// SHOULD I CREATE A SHIM OBJECT TO PROXY THIS FUNCTIONALITY?
// IS THERE A LOW COST MECHANISM TO DO THIS WITHOUT CREATING NEW OBJECTS?
impl Data {
    fn get_toolbar(&self) -> impl Toolbar {
        json.find(|x| x.message_type == MessageType::Toolbar) ????AS???? Toolbar // a view over the object for a toolbar
    }
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Avba
  • 14,822
  • 20
  • 92
  • 192

0 Answers0