Serde reference without new type

Time to time I meet such problem.
I have type like this:

use serde::{Deserialize, Serialize};
#[derive(Deserialize, Serialize, Debug)]
struct Foo {
  a: String,
  b: Vec<String>,
}

all works fine, I can serialize and deserialize to/from JSON.
But then I want to save &str and &[String] as Foo.
serde_json::to_something accepts &Foo, so from one hand
I don't have to allocate new memory, but if I don't want to define some weird struct like:

#[derive(Deserialize, Serialize, Debug)]
struct FooRef<'a> {
  a: &'a str,
  b: &'a [String],
}

I have to allocate new memory:

fn f(a: &str, b: &[String]) -> Result<String, Box<dyn std::error::Error> {
  let foo = Foo { 
     a: a.to_string(),
     b: b.iter().cloned().collect(),
  };
  let ret = serde_json::to_string(&foo)?;
  Ok(ret)

So, is any way avoid both definition of new struct just for this case and allocation new memory for old struct creation?

Maybe there's some macro out there that can generate FooRef for you, but besides that, no, you can't avoid it.

How about making the struct generic?

#[derive(Deserialize, Serialize, Debug)]
struct Foo<T, U> {
  a: T,
  b: U,
}

fn main() {
    let x: Foo<&str, &[&str]> = Foo {
        a: "hello",
        b: &["world", "!"],
    };
    let json = serde_json::to_string_pretty(&x).unwrap();

    println!("{}", json);

    let y: Foo<String, Vec<String>> = serde_json::from_str(&json).unwrap();

    println!("{:#?}", y);
}

Additionally, should you need to rely on the string-ness or slice-ness of the respective fields, you can always add AsRef<str> and AsRef<[String]> bounds, for example.

3 Likes