拥有的变量似乎没有发出借用的借用,而借用的借用则是serde的终身寿命

发布于 2025-01-22 00:09:11 字数 4390 浏览 3 评论 0原文

我正在尝试编写一个允许GZIP编码/解释任意(DE)序列化结构的特征。我的主要用例是通过干净的API在磁盘上持续一些状态结构。为此,每当struct s实现serde's serialize deserialialize 范围,gzzpipted +序列化的副本应由/写入/写入读取/按需写入/。

例如:

描述某些(DE)序列化结构的API的特征。

use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
use serde::{Serialize, Deserialize};
use rmp_serde::{Serializer};
use std::io::{Read, Write};

pub type Result<T, E = std::io::Error> = std::result::Result<T, E>;

pub trait ReadWriteState<S: Serialize + Deserialize> {
    /// Write the given persistent state to a stream.
    fn write_state(&mut self, state: &S) -> Result<usize>;
    /// Write the given persistent state to a stream.
    fn read_state(&mut self) -> Result<S>;
}

(de)可序列化状态以及通过任何std :: io :: Readstd :: io :: witr同时实现了读取词的读书。

impl<S, T> ReadWriteState<S> for T 
where
    S: Serialize + Deserialize, // This doesn't work because of lifetimes in serde Deserializer.
    T: Read + Write
{
    /// Serialize the state into messagepack and then
    /// GzEncode it before sending to the output stream.
    fn write_state(&mut self, state: &S) -> Result<usize> {
        let mut buf = Vec::new();
        state
            .serialize(&mut Serializer::new(&mut buf))
            .unwrap_or_else(|_| panic!("Could not serialize data."));

        let mut e = GzEncoder::new(Vec::new(), Compression::default());
        e.write_all(&buf)?;

        let compressed_bytes = e.finish()?;
        let length = compressed_bytes.len();

        self.write_all(&compressed_bytes)?;
    }

    /// Decode the gzipped stream into msgpack and then further deserialize it into the generic state struct.
    fn read_state(&mut self) -> Result<S, serde_json::Error> {
        let mut decoder = GzDecoder::new(self);
        let mut buf = Vec::new(); // The buf is created here so it is owned by this function scope.
        decoder.read_to_end(&mut buf).expect("Couldn't read the gzipped stream to end.");
        serde_json::from_slice::<'de, S>(&buf) // (*)

        // This is what I expect should work fine 
        // but the borrow checker complains that 
        // `buf` doesn't live long enough.
    }

}

serde_derive宏的样本状态结构(de)可序列化。

// Now suppose we have some struct that is Serialize as
// well as Deserialize.

#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct FooMap<K, V> 
where
    // For a moment, suppose Deserialize doesn't need a lifetime.
    // To compile, it should look more like Deserialize<'a> for some defined
    // lifetime 'a, but let's ignore that for a moment.
    K: Clone + Hash + Eq + Serialize + Deserialize,
    V: Eq + Serialize + Deserialize
{
    pub key: K,
    pub value: V
}

动作中的foomap方便的磁盘持久性API。

// Now I should be able to write gzipped + messagepacked FooMap to file.

pub fn main() {
    let foomap = FooMap {
        key: "color",
        value: "blue"
    };
    let mut file = std::fs::File::create("/tmp/foomap.gz").expect("Could not create file.");
    let bytes_written = file.write_state(&foomap).expect("Could not write state.");
    println!("{} bytes written to /tmp/foomap.gz", bytes_written);

    let mut file = std::fs::File::open("/tmp/foomap.gz").expect("Could not open file.");
    let recovered: FooMap<&str, &str> = file.read_state().expect("Could not recover FooMap.");
    assert_eq!(foomap, recovered);
}

您可能会注意到上面的代码问题。我知道的是,当用作特质绑定时,缺乏deperialize的终身注释。 Serde具有a 关于Deserializer寿命的美丽写入

我已经整理了一个试图解决生命周期的问题,然后,考虑到这种情况,我遇到了另一个编译器错误(*),这对我来说似乎很奇怪。

我真的很困惑,最终我走了一条错误的道路以及如何纠正它。如果有人可以帮助我了解我在实施中犯的错误,以及如何防止它再次发生,我将非常感谢。

I am trying to write a trait that allows for gzip encode/decode of arbitrary (de)serializable structs. My primary use case is to persist some stateful struct on disk via a clean API. To that end, any time a struct S implements serde's Serialize and Deserialize, and our trait is in scope, a gzipped + serialized copy of it should be read/written by/to anything that is Read/Write on demand.

For example:

A trait that describes the API for reading/writing of some (de)serializable struct.

use flate2::read::GzDecoder;
use flate2::write::GzEncoder;
use serde::{Serialize, Deserialize};
use rmp_serde::{Serializer};
use std::io::{Read, Write};

pub type Result<T, E = std::io::Error> = std::result::Result<T, E>;

pub trait ReadWriteState<S: Serialize + Deserialize> {
    /// Write the given persistent state to a stream.
    fn write_state(&mut self, state: &S) -> Result<usize>;
    /// Write the given persistent state to a stream.
    fn read_state(&mut self) -> Result<S>;
}

Blanket implementation of the ReadWriteState for (de)serializable states and via anything that is std::io::Read and std::io::Write simultaneously.

impl<S, T> ReadWriteState<S> for T 
where
    S: Serialize + Deserialize, // This doesn't work because of lifetimes in serde Deserializer.
    T: Read + Write
{
    /// Serialize the state into messagepack and then
    /// GzEncode it before sending to the output stream.
    fn write_state(&mut self, state: &S) -> Result<usize> {
        let mut buf = Vec::new();
        state
            .serialize(&mut Serializer::new(&mut buf))
            .unwrap_or_else(|_| panic!("Could not serialize data."));

        let mut e = GzEncoder::new(Vec::new(), Compression::default());
        e.write_all(&buf)?;

        let compressed_bytes = e.finish()?;
        let length = compressed_bytes.len();

        self.write_all(&compressed_bytes)?;
    }

    /// Decode the gzipped stream into msgpack and then further deserialize it into the generic state struct.
    fn read_state(&mut self) -> Result<S, serde_json::Error> {
        let mut decoder = GzDecoder::new(self);
        let mut buf = Vec::new(); // The buf is created here so it is owned by this function scope.
        decoder.read_to_end(&mut buf).expect("Couldn't read the gzipped stream to end.");
        serde_json::from_slice::<'de, S>(&buf) // (*)

        // This is what I expect should work fine 
        // but the borrow checker complains that 
        // `buf` doesn't live long enough.
    }

}

A sample stateful struct that is (de)serializable by serde_derive macros.

// Now suppose we have some struct that is Serialize as
// well as Deserialize.

#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
pub struct FooMap<K, V> 
where
    // For a moment, suppose Deserialize doesn't need a lifetime.
    // To compile, it should look more like Deserialize<'a> for some defined
    // lifetime 'a, but let's ignore that for a moment.
    K: Clone + Hash + Eq + Serialize + Deserialize,
    V: Eq + Serialize + Deserialize
{
    pub key: K,
    pub value: V
}

The convenient disk persistence API for our FooMap in action.

// Now I should be able to write gzipped + messagepacked FooMap to file.

pub fn main() {
    let foomap = FooMap {
        key: "color",
        value: "blue"
    };
    let mut file = std::fs::File::create("/tmp/foomap.gz").expect("Could not create file.");
    let bytes_written = file.write_state(&foomap).expect("Could not write state.");
    println!("{} bytes written to /tmp/foomap.gz", bytes_written);

    let mut file = std::fs::File::open("/tmp/foomap.gz").expect("Could not open file.");
    let recovered: FooMap<&str, &str> = file.read_state().expect("Could not recover FooMap.");
    assert_eq!(foomap, recovered);
}

You may notice a few problems with the code above. The one that I'm aware of is the lack of lifetime annotations for Deserialize when used as a trait bound. Serde has a beautiful write up regarding Deserializer lifetimes.

I've put together a Playground that tries to address the lifetime issue and by doing so, I've come across another compiler error (*) that seems pretty weird to me, given this situation.

I'm really confused at what point did I end up taking a wrong path and how to correct it. I would really appreciate if someone could help me understand the mistakes I've made in this implementation and how could I prevent it from happening again.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

栀梦 2025-01-29 00:09:11

如果您使用DeSerializened将代码编译为绑定,而不是deSerialize&lt;'de&gt;

serde的终身页面让这对deserialializeyneded (我的Highlights by Me):

这意味着“ T可以从任何生命周期中进行应有的序列化”。 Callee可以决定什么生命。 通常这是因为要从函数返回之前将被扔掉的数据将被扔掉,因此不得从中借入t。作为输入,将其从base64解码,值得t型T型值,然后丢弃基本64解码的结果。 [...]


这与您的用例完全匹配,因为buf在函数返回之前已删除。

Your code compiles if you use DeserializeOwned as a bound instead of Deserialize<'de>.

serde's lifetime page has this to say about DeserializeOwned (highlights by me):

This means "T can be deserialized from any lifetime." The callee gets to decide what lifetime. Usually this is because the data that is being deserialized from is going to be thrown away before the function returns, so T must not be allowed to borrow from it. For example a function that accepts base64-encoded data as input, decodes it from base64, deserializes a value of type T, then throws away the result of base64 decoding. [...]

This exactly matches your use case, since buf is dropped before the function returns.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文