How do I store a result using Serde Zero-copy deserialization of a Futures-enabled Hyper Chunk?

前端 未结 1 869
旧巷少年郎
旧巷少年郎 2021-01-19 10:39

I\'m using futures, tokio, hyper, and serde_json to request and deserialize some data that I need to hold until my next request. My initial thought was to make a struct cont

1条回答
  •  被撕碎了的回忆
    2021-01-19 10:44

    When trying to solve a complicated programming problem, it's very useful to remove as much as you can. Take your code and remove what you can until the problem goes away. Tweak your code a bit and keep removing until you can't any more. Then, turn the problem around and build from the smallest piece and work back to the error. Doing both of these will show you where the problem lies.

    First, let's make sure we deserialize correctly:

    extern crate serde;
    extern crate serde_json;
    #[macro_use]
    extern crate serde_derive;
    
    use std::borrow::Cow;
    
    #[derive(Debug, Deserialize)]
    pub struct Example<'a> {
        #[serde(borrow)]
        name: Cow<'a, str>,
        key: bool,
    }
    
    impl<'a> Example<'a> {
        fn info(&self) {
            println!("{:?}", self);
            match self.name {
                Cow::Borrowed(_) => println!("Is borrowed"),
                Cow::Owned(_) => println!("Is owned"),
            }
        }
    }
    
    fn main() {
        let data: Vec<_> = br#"{"key": true, "name": "alice"}"#.to_vec();
    
        let decoded: Example = serde_json::from_slice(&data).expect("Couldn't deserialize");
        decoded.info();
    }
    

    Here, I forgot to add the #[serde(borrow)] attribute, so I'm glad I did this test!

    Next, we can introduce the rental crate:

    #[macro_use]
    extern crate rental;
    
    rental! {
        mod holding {
            use super::*;
    
            #[rental]
            pub struct VecHolder {
                data: Vec,
                parsed: Example<'data>,
            }
        }
    }
    
    fn main() {
        let data: Vec<_> = br#"{"key": true, "name": "alice"}"#.to_vec();
    
        let holder = holding::VecHolder::try_new(data, |data| {
            serde_json::from_slice(data)
        });
        let holder = match holder {
            Ok(holder) => holder,
            Err(_) => panic!("Unable to construct rental"),
        };
    
        holder.rent(|example| example.info());
    
        // Make sure we can move the data and it's still valid
        let holder2 = { holder };
        holder2.rent(|example| example.info());
    }
    

    Next we try to create a rental of Chunk:

    #[rental]
    pub struct ChunkHolder {
        data: Chunk,
        parsed: Example<'data>,
    }
    

    Unfortunately, this fails:

      --> src/main.rs:29:1
       |
    29 | rental! {
       | ^
       |
       = help: message: Field `data` must have an angle-bracketed type parameter or be `String`.
    

    Oops! Checking the docs for rental, we can add #[target_ty_hack="[u8]"] to the data field. This leads to:

    error[E0277]: the trait bound `hyper::Chunk: rental::__rental_prelude::StableDeref` is not satisfied
      --> src/main.rs:29:1
       |
    29 | rental! {
       | ^ the trait `rental::__rental_prelude::StableDeref` is not implemented for `hyper::Chunk`
       |
       = note: required by `rental::__rental_prelude::static_assert_stable_deref`
    

    That's annoying; since we can't implement that trait for Chunk, we just need to box Chunk, proving that it has a stable address:

    #[rental]
    pub struct ChunkHolder {
        data: Box,
        parsed: Example<'data>,
    }
    

    I also looked to see if there is a way to get a Vec back out of Chunk, but it doesn't appear to exist. That would have been another solution with less allocation and indirection.

    At this point, "all" that's left is to integrate this back into the futures code. It's a lot of work for anyone but you to recreate that, but I don't foresee any obvious problems in doing so.

    0 讨论(0)
提交回复
热议问题