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

FR: Provide decode_inplace function #190

Open
mina86 opened this issue Jul 21, 2022 · 5 comments
Open

FR: Provide decode_inplace function #190

mina86 opened this issue Jul 21, 2022 · 5 comments

Comments

@mina86
Copy link
Contributor

mina86 commented Jul 21, 2022

Would be nice to have an in-place decode function, i.e.:

fn decode_inplace(data: &mut [u8]) -> Result<usize, DecodeError> {}

Since output is never longer than input, the decoded value can be saved directly into the input buffer thus possibly saving on having to allocate a new output buffer, e.g.:

fn b64decode(value: String) -> Result<Vec<u8>, base64::DecodeError> {
    let mut vec = value.into_bytes();
    let new_length = base64::decode_inplace(&mut vec[..])?;
    vec.truncate(new_length);
    Ok(vec)
}

This would of course come with a caveat that if error is encountered the data in the buffer is in unspecified state (portion of it could have been overwritten).

@Nugine
Copy link

Nugine commented Jul 28, 2022

https://docs.rs/base64-simd/latest/base64_simd/struct.Base64.html#method.decode_inplace

fn b64decode(value: String) -> Result<Vec<u8>, base64_simd::Error> {
    let base64 = base64_simd::Base64::STANDARD;
    let mut vec = value.into_bytes();
    let new_length = base64.decode_inplace(&mut vec)?.len();
    vec.truncate(new_length);
    Ok(vec)
}

@marshallpierce
Copy link
Owner

I can see the appeal in general of not requiring more memory footprint than necessary. Do you have a specific use case in mind? Does this functionality need to extend to anything beyond a function that decodes in place in order to be useful?

@mina86
Copy link
Contributor Author

mina86 commented Dec 1, 2022

There are two cases:

  1. I have a String which I want to decode into Vec. With decode_inline I can do it with zero allocations reusing String’s internal vector.
  2. I have an encoded data in a String which (after decoding) is further deserialised into an actual object I want. Again, with decode_inline I can decode it reusing String’s Vec and then deserialise bytes from there. Though to be honest I cannot find an example of that now and I’m not 100% sure this is still an issue for me.

Function decoding in place would be sufficient.

By the way, I realised that there is one complication. If I understand base58 correctly, decoding happens from the end so the first byte that is known is the last byte in the buffer. This means that decode_inplace would store the data at the end of the buffer. This would complicate the first use case and require the use of Vec::copy_within. Still, that’s probably better than having to allocate a new Vector.

@marshallpierce
Copy link
Owner

Not sure about base58, but base64 decodes in front to back order in groups of 4 tokens, so that problem at least does not apply.

@mina86
Copy link
Contributor Author

mina86 commented Dec 3, 2022

Ah, sorry, I was reading this Issue thinking this was bs58 repository. Indeed, with base64 the last paragraph is not relevant.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants