Arthur's Blog

Create a Custom Deserializer in Rust's deser

2025-11-05 || Tags: rust quick reminder programming

Writing a custom deserializer can be very helpful. Often I already have a specific struct that I want to use that only matches 90% to the struct I'm trying to deserialize. Here's a quick way on how to do it.

This is for use with rust's serde library. Seems to be the go to for serialization (and de-) in rust.

NOTE: I am a very new rust developer, do not take any of this as any gospel. Don't ask me about the de stuff for example.

Deserialize using a Function

Here's a minimal example which seems to come up a lot for me.

use serde::Deserialize;
use serde::de::Deserializer;

fn parse_doc_id<'de, D>(deserializer: D) -> Result<PatentDetails, D::Error>
where
    D: Deserializer<'de>,
{
	// These 2 structures describe the format of JSON I'm receiving
    #[derive(Debug, Deserialize)]
    pub struct RegDocumentId {
        #[serde(rename(deserialize = "reg:country"))]
        pub reg_country: DollarValue,
        #[serde(rename(deserialize = "reg:doc-number"))]
        pub reg_doc_number: DollarValue,
        #[serde(rename(deserialize = "reg:date"))]
        pub reg_date: Option<DollarValue>,
    }
    #[derive(Debug, Deserialize)]
    pub struct DollarValue {
        #[serde(rename(deserialize = "$"))]
        pub value: String,
    }

	// Deserialize it
    let reg_doc_id = RegDocumentId::deserialize(deserializer)?;

	// Do whatever custom stuff you want
    let date = reg_doc_id
        .reg_date
        .map(|d| NaiveDate::parse_from_str(&d.value, "%Y%m%d").unwrap());
		
	// Return the struct I want
    Ok(PatentDetails {
        country_code: reg_doc_id.reg_country.value.clone(),
        number: reg_doc_id.reg_doc_number.value.clone(),
        date,
        kind_code: None,
        reference_type: PatentReferenceType::Unknown,
    })
}

#[derive(Debug, Deserialize)]
pub struct RegApplicationReference {
    #[serde(
        rename(deserialize = "reg:document-id"), // Because the JSON has a weird field key
        deserialize_with = "parse_doc_id"        // Note same function name as above
    )]
    pub reg_document_id: PatentDetails,
}

/// In some other part of your project
///...
let doc_ref: RegApplicationReference =
                    serde_json::from_reader(reader).expect("JSON was not well formatted");
					
// Should be in your nice "custom" data type now
let blah = doc_ref.do_something_youve_implemented_on_that_struct_previously();

Hopefully this is enough of an example to let you know what to do next.

Why I Like This

Why It Could Be Bad

Alternatives