Skip to content

Refactor encoding and decoding to use MaybeUninit for improved safety and flexibility#6

Merged
cfcosta merged 1 commit intocfcosta:mainfrom
biryukovmaxim:main
Nov 8, 2025
Merged

Refactor encoding and decoding to use MaybeUninit for improved safety and flexibility#6
cfcosta merged 1 commit intocfcosta:mainfrom
biryukovmaxim:main

Conversation

@biryukovmaxim
Copy link
Contributor

Summary

This PR refactors the crate to use MaybeUninit properly, fixing safety violations while improving flexibility and performance.

Changes

1. Fixed Safety Violations

The original decode function violated Vec::set_len() safety contract:

Before (Line 188):

let mut output = Vec::with_capacity(output_len);
unsafe {
    output.set_len(output_len);  // ❌ Claims uninitialized memory is initialized
}
decode_into(input, &mut output)?;  // If this fails, Vec drops with uninit bytes

Problem: Vec::set_len() requires that "all elements in 0..new_len must be initialized." This code violated that contract by marking memory as initialized before actually writing to it.

After:

let mut output = Vec::with_capacity(output_len);
decode_into(input, output.spare_capacity_mut())?;  // ✅ Work with MaybeUninit
unsafe {
    output.set_len(output_len);  // ✅ Only mark initialized after successful write
}

Now set_len() is only called after bytes are actually initialized, fully respecting safety invariants.

2. Introduced Buf Trait for Flexibility

Added a Buf trait that abstracts over buffer types:

pub trait Buf {
    fn dst(&mut self) -> &mut [MaybeUninit<u8>];
}

impl Buf for [MaybeUninit<u8>] { ... }
impl Buf for [u8] { ... }  // Enables working with pre-allocated buffers

Benefits:

Example with fixed_str (my use case: 32-byte hash Display implementations):

use fixed_str::FixedStr;
let hash: [u8; 32] = [1u8; 32];
let mut s = [MaybeUninit::uninit(); 64];
encode_to_buf(&hash, s.as_mut_slice()).unwrap();
let hex_str: FixedStr<64> =
FixedStr::from_bytes(unsafe { std::mem::transmute(s) });
println!("{}", hex_str);

3. Performance Improvements

Encoding now outperforms faster-hex:

muhex:       54.97 µs [17.76 GiB/s]
faster-hex:  79.30 µs [12.31 GiB/s]

~29% faster throughput on encoding operations.

@cfcosta
Copy link
Owner

cfcosta commented Nov 8, 2025

image

Surprisingly, it was not faster here, maybe because of different processor architectures. However, I learned something today, first time hearing about MaybeUninit!

Thanks for the PR <3

@cfcosta cfcosta merged commit 8e02110 into cfcosta:main Nov 8, 2025
1 of 2 checks passed
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

Successfully merging this pull request may close these issues.

2 participants