Idiomatic way to write adapter struct

I have a GradescopeTestReport struct which conforms to a particular format required by the Gradescope website and I have a TestReport struct that uses types more specific to my use case. The two structs have identical fields but slightly different types:

#[derive(Serialize, Deserialize, Clone)]
pub struct TestReport {
    score: f32,
    max_score: f32,
    name: String,
    number: usize,
    output: Option<String>,
    tags: Option<std::vec::Vec<String>>,
    visibility: Option<Visibility>,
}

#[derive(Serialize, Deserialize, Clone)]
pub struct GradescopeTestReport {
    score: String,
    max_score: f32,
    name: String,
    number: String,
    output: Option<String>,
    tags: Option<std::vec::Vec<String>>,
    visibility: Option<Visibility>,
}

impl From<TestReport> for GradescopeTestReport {
    fn from(report: TestReport) -> Self {
        GradescopeTestReport {
            score: report.score.to_string(),
            max_score: report.max_score,
            name: report.name,
            number: report.number.to_string(),
            output: report.output,
            tags: report.tags,
            visibility: report.visibility,
        }
    }
}

Is there a way to write this that avoids all the boilerplate?

check out serde's serialize_with and deserialize_with attributes

https://serde.rs/variant-attrs.html#serialize_with

Nice! This is what I came up with:

fn to_str<S, T>(float: &T, s: S) -> Result<S::Ok, S::Error>
where
    S: Serializer,
    T: std::fmt::Display,
{
    s.serialize_str(&*float.to_string())
}

#[derive(Serialize, Deserialize, Clone)]
pub struct TestReport {
    #[serde(serialize_with = "to_str")]
    score: f32,
    max_score: f32,
    name: String,
    #[serde(serialize_with = "to_str")]
    number: usize,
    output: Option<String>,
    tags: Option<std::vec::Vec<String>>,
    visibility: Option<Visibility>,
}
1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.