I have multiple structs that correspond to serialized/deserialized objects only known during runtime, example:
#[derive(Serialize, Deserialize)]
struct Car{
model: i32,
year: i32
}
#[derive(Serialize, Deserialize)]
struct Person{
name: String,
age: i32
}
Then I have functions to serialize and deserialize:
fn deserialize(data: Vec<u8>){
let msg = str::from_utf8(data);
serde_json::from_str(msg);
}
fn serialize(&self, object: Car) -> String{
let msg = serde_json::to_string(&object).unwrap();
return msg;
}
How can I make the deserialize function deserialize to both Car and Person (and possibly many other different types) and return the object? And how can I make the serialize function do the same thing: serialize Car, Person, and other objects (accepting these types in the attributes of the function)?
You want to use generic functions to allow different types to be passed in, and set trait bounds to make sure the objects are able to be serialized/deserialized. When calling serialize
, the type will be inferred by the type of the parameter, but when calling deserialize
, you need to use the turbofish (::<>
) to specify the type, if it can't be inferred.
use serde::{Serialize, Deserialize};
use std::str;
#[derive(Serialize, Deserialize)]
struct Car {
model: i32,
year: i32
}
#[derive(Serialize, Deserialize)]
struct Person {
name: String,
age: i32
}
// constrain output types to have the `Deserialize` trait
fn deserialize<'a, T>(data: &'a [u8]) -> T where T: Deserialize<'a> {
let msg = str::from_utf8(data).unwrap();
serde_json::from_str::<T>(msg).unwrap()
}
// shorthand for the above when `T` isn't needed in the function body
fn serialize(object: &impl Serialize) -> String {
let msg = serde_json::to_string(object).unwrap();
return msg;
}
fn main() {
let car = Car { model: 7, year: 2077 };
let person = Person { name: "Bob".to_string(), age: 42 };
// types are infrerred from the parameters
let car_json = serialize(&car);
let person_json = serialize(&person);
let _: Car = deserialize(car_json.as_bytes()); // output type can be inferred
let _ = deserialize::<Car>(car_json.as_bytes()); // requres turbofish
let _: Person = deserialize(person_json.as_bytes()); // works for `Person` too
}