Zero-copy deserialization in generic function
⚓ Rust 📅 2025-05-11 👤 surdeus 👁️ 12I'm trying to deserialize a generic type T in a function without requiring that T: DeserializeOwned, but just that T: Deserialize, i.e. I would like to permit it to borrow from the input. However I don't see a way to make this work. Consider this code:
use std::fmt;
use serde::Deserialize;
#[derive(Debug, Deserialize)]
struct Foo<T> {
#[allow(dead_code)]
bar: T,
}
fn main() {
deserialize_and_print();
deserialize_generic_and_print::<Foo<&str>>();
}
fn deserialize_and_print() {
let s = r#"{ bar: "baz" }"#.to_string();
let foo: Foo<&str> = serde_json::from_str(&s).unwrap();
println!("{foo:?}");
}
fn deserialize_generic_and_print<T: fmt::Debug + Deserialize>() {
let s = r#"{ bar: "baz" }"#.to_string();
let foo: Foo<T> = serde_json::from_str(&s).unwrap();
println!("{foo:?}");
}
The non-generic function deserialize_and_print works perfectly fine, but this code does not compile because the Deserialize bound in deserialize_generic_and_print is missing a lifetime.
But how can I fill out this lifetime? I don't want the caller to choose a lifetime and it certainly can't just be any lifetime. The way I think about it, I want to specify the lifetime of a local variable of the function, i.e. the lifetime of s. But I'm not aware of any way to do that. Conceptually I want to write this basically:
// Note the lack of a generic lifetime parameter.
fn deserialize_generic_and_print<T: fmt::Debug + Deserialize<'s>>() {
's: {
let s = r#"{ bar: "qux" }"#.to_string();
let foo: Foo<T> = serde_json::from_str(&s).unwrap();
println!("{foo:?}");
}
}
If I try to just fill in a generic lifetime like this...
fn deserialize_generic_and_print<'s, T: fmt::Debug + Deserialize<'s>>() {
let s = r#"{ bar: "qux" }"#.to_string();
let foo: Foo<T> = serde_json::from_str(&s).unwrap();
println!("{foo:?}");
}
I get borrowed value does not live long enough and s dropped here [at the end of the function] while still borrowed, because the caller could in principle choose a lifetime that is longer than the lifetime of s - but is there no way to restrict the caller to not allow any lifetime longer than a local variable of the function?
I'd like to know whether I am running up against some kind of misunderstanding or fundamental limitation of the borrow checker, or whether the issue is a lack of a way to specify that "local variable lifetime".
1 post - 1 participant
🏷️ rust_feed