How do you make a Serde struct work with both borrowed and owned data?
Asked Answered
D

1

9

I want to make a Serde struct that is capable of being deserialized from either borrowed data (serde_json::from_str) or owned data (serde_json::from_reader). I have read Understanding deserializer lifetimes, and I understand the difference between the two trait bounds (<'de, T> where T: Deserialize<'de> and <T> where T: DeserializeOwned); what I want is a struct that implements both trait bounds, such that it can be used from either deserialization function.

The following code (playground) refuses to compile:

use serde_json; // 1.0.56
use serde; // 1.0.114
use std::fs;
use std::io;
use std::borrow::Cow;

#[derive(serde::Deserialize)]
struct Resource<'s> {
    // The Cow should allow for either borrowed or owned data
    #[serde(borrow)]
    pub foo: Cow<'s, str>,
}

fn main() {
    {
        // Works as expected when referencing a string...
        let s = "{\"foo\":\"bar\"}";
        let resource: Resource = serde_json::from_str(s).unwrap();
    }
    {
        // ...but refuses to compile when reading from a file
        let file = fs::File::open("dummy.json").unwrap();
        let reader = io::BufReader::new(file);
        let resource: Resource = serde_json::from_reader(reader).unwrap();
    }
}

How do I make this struct work with both owned and borrowed data? Is there a way to do something like #[serde(borrow_optional)]?

Durango answered 1/8, 2020 at 4:0 Comment(0)
M
1

(playground link)

It's not possible with the constraints on serde_json::from_reader. However, it is possible if you construct Deserializer yourself:

        // ...but refuses to compile when reading from a file
        let file = fs::File::open("dummy.json").unwrap();
        let reader = io::BufReader::new(file);
        let mut deser = serde_json::Deserializer::from_reader(reader);
        let resource = Resource::deserialize(&mut deser).unwrap();
Mcmaster answered 9/2, 2022 at 7:2 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.