wiwi/encoding/hex/
encode.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//! Internal encoding implementations

use super::UnsafeBufWriteGuard;

/// Length of encoding table (not actually used in encoding/decoding data)
pub const TABLE_ENCODER_LEN: usize = 16;

/// Encoding table of lowercased characters, length 16, mapping a value from 0-15
/// to a hex byte (lower letters)
///
/// Note: this table is not actually used in the encoding/decoding implementation
pub static TABLE_ENCODER_LOWER: [u8; TABLE_ENCODER_LEN] = *b"0123456789abcdef";

/// Encoding table of uppercased characters, length 16, mapping a value from 0-15
/// to a hex byte (upper letters)
///
/// Note: this table is not actually used in the encoding/decoding implementation
pub static TABLE_ENCODER_UPPER: [u8; TABLE_ENCODER_LEN] = *b"0123456789ABCDEF";

/// Reads `rounds` bytes from `bytes_ptr`, encoding them into 2 hex chars
/// per byte, then writes the output into `dest`
///
/// # SAFETY
///
/// - `bytes_ptr` must be valid for `num_rounds` bytes of reads
/// - `dest` must have enough capacity to write `num_rounds * 2` bytes into
pub unsafe fn generic<const UPPER: bool>(
	mut bytes_ptr: *const u8,
	dest: &mut UnsafeBufWriteGuard,
	rounds: usize
) {
	let char_a = if UPPER { b'A' } else { b'a' } - 10;
	let char_0 = b'0';

	for _ in 0..rounds {
		// SAFETY: we loop `num_rounds` times only, reading a byte each time,
		// and caller promises that `bytes_ptr` is valid to read for at least
		// that many bytes
		let byte = unsafe { *bytes_ptr };

		// SAFETY: same invariant as above. It's sound to have the pointer pointing
		// to the end of the memory section (as long as it isn't dereferenced)
		bytes_ptr = unsafe { bytes_ptr.add(1) };

		let char1 = byte >> 4;
		let char2 = byte & 0xf;

		let chars = [
			if char1 > 9 { char_a } else { char_0 } + char1,
			if char2 > 9 { char_a } else { char_0 } + char2
		];

		// SAFETY: caller guarantees `dest` is writeable to for at least
		// `num_rounds * 2` bytes, so we can write 2 bytes every iteration
		unsafe { dest.write_bytes_const::<2>(chars.as_ptr()) }
	}
}