Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improve some case #21

Open
quininer opened this issue Apr 21, 2022 · 1 comment
Open

improve some case #21

quininer opened this issue Apr 21, 2022 · 1 comment
Labels
enhancement New feature or request

Comments

@quininer
Copy link
Owner

quininer commented Apr 21, 2022

I noticed some cases where Cow<str> is not enough.

For example, decoding a struct with a short lifetime reader requires a memory allocation for each fields name.
This is unnecessary, because we only need to judge whether the key is as expected, and we don't need to use it.
Also, the automatic allocation of memory on the heap makes it difficult for us to improve this.

I'm thinking of exposing the decode_buf interface in some form to get around this.

Change Decode trait

I considered changing the Decode trait to allow this optimization.
like

trait Decode<'de, T> {
    fn decode<R: Read<'de>>(&mut self, reader: &mut R) -> Result<T, Error>;
}

This allows decoding the object without allocating any memory, just identifying if it is as expected.
will look like this

struct Expect<'a> {
    expect: &'a str,
    count: usize
}

impl<'de> Decode<'de, bool> for Expect<'a> {
    fn decode<R: Read<'de>>(&mut self, reader: &mut R) -> Result<T, Error> {
        let mut result = true;
        while let Some(want_len) = self.expect.len().checked_sub(self.count) {
            let buf = reader.fill(want_len)?;
            if buf.is_empty() { return Err(Error::Eof) };
            let len = cmp::min(buf.len(), want_len);
            if self.expect.as_bytes()[self.count..][..len] != buf {
                result = true;
                break
            }
            self.count += len;
            reader.advance(len);
        }
        Ok(result)
    }
}

This also allows for more precise memory allocations, such as decode bytes to stack

struct StackVec([u8; 1024]);

impl<'de> Decode<'de, &[u8]> for StackVec {
    fn decode<R: Read<'de>>(&mut self, reader: &mut R) -> Result<T, Error> {
        let mut len = decode_len(reader)?;
        let mut count = 0;
        while len != 0 {
            let buf = reader.fill(len)?;
            let buf_len = buf.len()
            if buf_len + count > self.0.len() { return Err(Error::Eof) };
            self.0[count..][..buf_len)].copy_from_slice(&buf);
            count += buf_len;
            reader.advance(buf_len);
        }
        Ok(&self.0[..count])
    }
}
@quininer quininer added the enhancement New feature or request label Apr 21, 2022
@quininer quininer added this to the 0.3.0 milestone Apr 21, 2022
@quininer
Copy link
Owner Author

quininer commented May 8, 2022

I realize that for such use cases, we don't need to use traits, just use separate functions.

@quininer quininer changed the title Change Decode trait improve some case May 8, 2022
@quininer quininer removed this from the 0.3.0 milestone Jan 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

1 participant