I have two structs:
#[derive(Serialize)]
struct Post {
title: String,
// ...more fields...,
comments: Vec<Comment>,
}
#[derive(Serialize)]
struct Comment {
body: String,
// ...more fields...,
}
I want to generate 2 kinds of JSON files:
Vec<Post>
which should include all fields except comments
.Post
which includes all fields.Is it possible to achieve this with the Serialize
derive attribute? I found skip_serializing_if
attribute in Serde's documentation but as far as I can see, it's not useful for me because I want to skip not based on the value of the field but based on which JSON file I'm generating.
Right now I'm generating the index using the json!
macro which requires manually listing all the fields of Post
but I'm hoping there's a better way to do this.
Serde. Serde, the incumbent serialization/deserialization library, is elegant, flexible, fast to run, and slow to compile.
Serde is a framework for serializing and deserializing Rust data structures efficiently and generically. The Serde ecosystem consists of data structures that know how to serialize and deserialize themselves along with data formats that know how to serialize and deserialize other things.
Serde is really designed to be fast, by allowing fully statically dispatched operations without runtime reflections so formats and types are decoupled at code but transparent to the optimization. It's serde_json which cares all the weirdnesses of the JSON format.
Serde JSON JSON is a ubiquitous open-standard format that uses human-readable text to transmit data objects consisting of key-value pairs.
I want to generate 2 kinds of JSON files
I read that as "2 types of JSON files", so I turn towards that as a solution. I'd create wrapper types custom-fit to each context. These can take references to the original type to avoid too much memory overhead:
#[derive(Serialize)]
struct LightweightPost<'a> {
title: &'a String,
}
impl<'a> From<&'a Post> for LightweightPost<'a> {
fn from(other: &'a Post) -> Self {
LightweightPost {
title: &other.title,
}
}
}
fn main() {
let posts = vec![
Post {
title: "title".into(),
comments: vec![Comment { body: "comment".into() }],
},
];
let listing: Vec<_> = posts.iter().map(LightweightPost::from).collect();
println!("{}", serde_json::to_string(&listing).unwrap());
// [{"title":"title"}]
println!("{}", serde_json::to_string(&posts[0]).unwrap());
// {"title":"title","comments":[{"body":"comment"}]}
}
playground
Editorially, I've found this type of multiple-type structure very useful when writing web apps in Ruby, using the roar gem. These new types allow for places to hang behavior specific to certain contexts such as validation or persistence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With