Search code examples
rustserdeserde-json

How to partially deserialise a JSON object?


I have a JSON object:

{"content":{"foo":1,"bar":2},"signature":"3f5ab1..."}

Deserialising this into a custom type already works fine, using:

let s: SignedContent = serde_json::from_str(string)?;

What I want is {"foo":1,"bar":2} as a &[u8] slice, so that I can check the signature.

(I am aware of the issues around canonical JSON representations, and have mitigations in place.)

Currently I am wastefully re-serialising the Content object (within the SignedContent object) into a string and getting the octets from that.

Is there a more efficient way?


Solution

  • Looks like a job for serde_json::value::RawValue (which is available with the "raw_value" feature).

    Reference to a range of bytes encompassing a single valid JSON value in the input data.

    A RawValue can be used to defer parsing parts of a payload until later, or to avoid parsing it at all in the case that part of the payload just needs to be transferred verbatim into a different output object.

    When serializing, a value of this type will retain its original formatting and will not be minified or pretty-printed.

    With usage being:

    #[derive(Deserialize)]
    struct SignedContent<'a> {
    
        #[serde(borrow)]
        content: &'a RawValue,
    
        // or without the 'a
        //content: Box<RawValue>
    }
    

    You can then use content.get() to get the raw &str.