Skip to content

Add Encoding::encode_mut_str #136

Closed
@zacknewman

Description

@zacknewman

Would it be possible to add a method like Encoding::encode_mut except have it return &str instead of ()? The purpose of such a method would be to allow for downstream code to use stack-allocated strings without having to use unsafe code or call core::str::from_utf8 and incur unnecessary overhead of UTF-8 validation.

Essentially the method would look similar to below with possible changes to call str::from_utf8_unchecked on a sub-slice of output in the event it's not guaranteed the entirety of output would be written to:

pub fn encode_mut_str<'a: 'b, 'b>(&self, input: &[u8], output: &'a mut [u8]) -> &'b str {
    self.encode_mut(input, output);
    // SAFETY:
    // Encoded data is always valid UTF-8.
    unsafe { str::from_utf8_unchecked(output) }
}

Currently downstream code is forced to do either

use data_encoding::BASE64URL_NOPAD;
pub fn foo() {
    let input = [0];
    let mut output = [0; 2];
    BASE64URL_NOPAD.encode_mut(input.as_slice(), output.as_mut_slice());
    // SAFETY:
    // `data_encoding::Encoding::encode_mut` always encodes UTF-8 data.
    let val = unsafe { str::from_utf8_unchecked(output.as_slice()) };
}

or

use data_encoding::BASE64URL_NOPAD;
pub fn foo() {
    let input = [0];
    let mut output = [0; 2];
    BASE64URL_NOPAD.encode_mut(input.as_slice(), output.as_mut_slice());
    let val = str::from_utf8(output.as_slice()).unwrap_or_else(|_e| unreachable!("there is a bug in data_encoding::Encoding::encode_mut"));
}

With encode_mut_str, then the above could be written like:

use data_encoding::BASE64URL_NOPAD;
pub fn foo() {
    let input = [0];
    let mut output = [0; 2];
    let val = BASE64URL_NOPAD.encode_mut_str(input.as_slice(), output.as_mut_slice());
}

When unsafe code is used, it's a lot better for the code to be entirely localized and not have to rely on an external crate to uphold the safety invariants. I realize this can be considered micro-optimization, but I thought I'd ask.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions