cbor4ii
cbor4ii copied to clipboard
improve some case
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])
}
}
I realize that for such use cases, we don't need to use traits, just use separate functions.