user14325
user14325

Reputation: 392

How can I serialize a struct into a format that has dynamic keys in rust using Serde

I have a struct similar to

pub struct FooBarList {
    items: Vec<FooBar>,
    name: String
}

pub struct FooBar {
    pub foo: i32,
    pub bar: i32
}

I need to serialize this into a flattened format i.e. something like

{
    "name": "foo",
    "foo1": 0,
    "bar1": 41,
    "foo2": 43,
    "bar2": 12,
...
}

I tried doing the following:

impl Serialize for FooBarList {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let item_count = self.items.len();

        let mut struct_ser = serializer.serialize_struct("FooBarList", 1 + 2 * item_count)?;

        for (i, item) in (&self.items).into_iter().enumerate() {
            struct_ser.serialize_field(format!("foo{}", i + 1).as_str(), &item.foo)?;
            struct_ser.serialize_field(format!("bar{}", i + 1).as_str(), &item.bar)?;
        }

        struct_ser.serialize_field("name", &self.name)?;

        struct_ser.end()
    }
}

This fails however, because struct_ser.serialize_field() requires &'static str as the first parameter, but the &str produced by format!().as_str() has a non-static lifetime. I don't see a way to create the strings statically, as length of the number of items is only known at runtime. Is there any way to circumvent that limitation?

Upvotes: 1

Views: 897

Answers (1)

Chayim Friedman
Chayim Friedman

Reputation: 71430

You can serialize it as a map using serialize_map():

impl Serialize for FooBarList {
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: serde::Serializer,
    {
        let item_count = self.items.len();

        let mut struct_ser = serializer.serialize_map(Some(1 + 2 * item_count))?;

        for (i, item) in (&self.items).into_iter().enumerate() {
            struct_ser.serialize_entry(&format!("foo{}", i + 1), &item.foo)?;
            struct_ser.serialize_entry(&format!("bar{}", i + 1), &item.bar)?;
        }

        struct_ser.serialize_entry("name", &self.name)?;

        struct_ser.end()
    }
}

You can't give a name to the struct in this way, though.

Upvotes: 2

Related Questions