How to implement `serde::Serialize` for a boxed trait object?

帅比萌擦擦* 提交于 2019-11-29 10:50:07

For serializing Serde trait objects you should use erased-serde.

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate erased_serde;

extern crate serde;
extern crate serde_json;

#[derive(Serialize)]
struct Card {
    sections: Vec<Section>,
}

#[derive(Serialize)]
struct Section {
    header: String,
    widgets: Vec<Box<WidgetTrait>>,
}

#[derive(Serialize)]
struct Image {
    image_url: String,
}

#[derive(Serialize)]
struct KeyValue {
    top_label: String,
    content: String,
}

trait WidgetTrait: erased_serde::Serialize {}
impl WidgetTrait for Image {}
impl WidgetTrait for KeyValue {}

serialize_trait_object!(WidgetTrait);

fn main() {
    let card = Card {
        sections: vec![
            Section {
                header: "text".to_owned(),
                widgets: vec![
                    Box::new(Image {
                        image_url: "img".to_owned(),
                    }),
                    Box::new(KeyValue {
                        top_label: "text".to_owned(),
                        content: "text".to_owned(),
                    }),
                ],
            },
        ],
    };

    println!("{}", serde_json::to_string_pretty(&card).unwrap());
}
snowbane

I got around the compiler errors:

#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

use serde::ser::{Serialize, Serializer, SerializeStruct};

#[derive(Serialize)]
struct Card {
    sections: Vec<Section>
}

#[derive(Serialize)]
struct Section {
    header: String,
    widgets: Vec<Box<WidgetTrait>>
}

#[derive(Serialize)]
struct Image {
    #[serde(rename = "imageUrl")]
    image_url: String
}

#[derive(Serialize)]
struct KeyValue {
    #[serde(rename = "topLabel")]
    top_label: String,

    content: String
}

trait WidgetTrait {}

impl Serialize for WidgetTrait {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
        where S: Serializer {
            let s = serializer.serialize_struct("???", 3)?;

            s.end()
        }
}

impl WidgetTrait for Image {}
impl WidgetTrait for KeyValue {}

fn main() {
    // let test = ResponseMessage { 
    //         text: None, 
    //         cards: Some(
    //             vec![Card { sections: vec![
    //                 Section { header: format!("text"), widgets: vec![ 
    //                     Box::new(Image { image_url: format!("img") }) 
    //                     ]},
    //                 Section { header: format!("text"), widgets: vec![
    //                      Box::new(KeyValue { top_label: format!("text"), content: format!("text") }),
    //                      Box::new(KeyValue { top_label: format!("text"), content: format!("text") })
    //                      ]}
    //                 ]}])
    //         }
}

Playground


Steps for a working solution.

  1. Write as_any() implementations for your structs that implement WidgetTrait as per How to get a struct reference from a boxed trait?.
  2. Add implementation for trait Serialize of type Box<WidgetTrait>
  3. Downcast Box<Widget> to the struct so we know the type using as_any() and downcast_ref()
  4. Use documentation on how to serialize a strongly typed struct
#[macro_use]
extern crate serde_derive;
extern crate serde_json;
extern crate serde;

use serde::ser::{Serialize, Serializer, SerializeStruct};
use std::any::Any;

#[derive(Serialize)]
struct Card {
    sections: Vec<Section>
}

#[derive(Serialize)]
struct Section {
    header: String,
    widgets: Vec<Box<WidgetTrait>>
}

#[derive(Serialize)]
struct Image {
    #[serde(rename = "imageUrl")]
    image_url: String
}

#[derive(Serialize)]
struct KeyValue {
    #[serde(rename = "topLabel")]
    top_label: String,

    content: String
}

trait WidgetTrait {
    fn as_any(&self) -> &Any;
}

impl Serialize for Box<WidgetTrait> {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> 
        where S: Serializer {
            return match self.as_any().downcast_ref::<Image>() {
                Some(img) => {
                        let mut widget_serializer = serializer.serialize_struct("Image", 1)?;
                        widget_serializer.serialize_field("imageUrl", &img.image_url)?;

                        widget_serializer.end()  
                    },
                None => {
                    let key_value: &KeyValue = match self.as_any().downcast_ref::<KeyValue>() {
                        Some(k) => k,
                        None => panic!("Unknown type!")
                    };

                    let mut widget_serializer = serializer.serialize_struct("KeyValue", 2)?;
                    widget_serializer.serialize_field("topLabel", &key_value.top_label)?;
                    widget_serializer.serialize_field("content", &key_value.content)?;

                    widget_serializer.end()  
                }
            };                
        }
}

impl WidgetTrait for Image {
    fn as_any(&self) -> &Any {
        self
    }
}

impl WidgetTrait for KeyValue {
    fn as_any(&self) -> &Any {
        self
    }
}

fn main() {
    // let test = ResponseMessage { 
    //         text: None, 
    //         cards: Some(
    //             vec![Card { sections: vec![
    //                 Section { header: format!("text"), widgets: vec![ 
    //                     Box::new(Image { image_url: format!("img") }) 
    //                     ]},
    //                 Section { header: format!("text"), widgets: vec![
    //                      Box::new(KeyValue { top_label: format!("text"), content: format!("text") }),
    //                      Box::new(KeyValue { top_label: format!("text"), content: format!("text") })
    //                      ]}
    //                 ]}])
    //         }
}

Playground

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!