aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2026-02-14 13:57:02 +0100
committerJeroen van Rijn <Kelimion@users.noreply.github.com>2026-02-14 13:57:02 +0100
commit2622c1ab993cdc422fee96a99beb33c73dafa1d1 (patch)
tree8584c6002ccfbd4fceb7af0845448686fb9d0553
parent4c9466e3ea6943911971c62dd57c59bba886cfef (diff)
Fix #6229
Fixes #6229 by adding `encode_upper` and `encode_upper_into_writer`. Also updated the documentation to be more like the rest of `core`.
-rw-r--r--core/encoding/hex/hex.odin124
1 files changed, 110 insertions, 14 deletions
diff --git a/core/encoding/hex/hex.odin b/core/encoding/hex/hex.odin
index 318e52ace..c4726d9e9 100644
--- a/core/encoding/hex/hex.odin
+++ b/core/encoding/hex/hex.odin
@@ -1,35 +1,115 @@
// Encoding and decoding of hex-encoded binary, e.g. `0x23` -> `#`.
package encoding_hex
+import "base:runtime"
import "core:io"
import "core:strings"
-encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> []byte #no_bounds_check {
- dst := make([]byte, len(src) * 2, allocator, loc)
- for i, j := 0, 0; i < len(src); i += 1 {
+/*
+Encodes a byte slice into a lowercase hex sequence
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- src: The `[]byte` to be hex-encoded
+- allocator: (default: context.allocator)
+- loc: The caller location for debugging purposes (default: #caller_location)
+
+Returns:
+- res: The hex-encoded result
+- err: An optional allocator error if one occured, `.None` otherwise
+*/
+encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) #optional_allocator_error {
+ res, err = make([]byte, len(src) * 2, allocator, loc)
+ #no_bounds_check for i, j := 0, 0; i < len(src); i += 1 {
v := src[i]
- dst[j] = HEXTABLE[v>>4]
- dst[j+1] = HEXTABLE[v&0x0f]
+ res[j] = LOWER[v>>4]
+ res[j+1] = LOWER[v&0x0f]
j += 2
}
+ return
+}
+
+/*
+Encodes a byte slice as a lowercase hex sequence into an `io.Writer`
+
+Inputs:
+- dst: The `io.Writer` to encode into
+- src: The `[]byte` to be hex-encoded
+
+Returns:
+- err: An `io.Error` if one occured, `.None` otherwise
+*/
+encode_into_writer :: proc(dst: io.Writer, src: []byte) -> (err: io.Error) {
+ for v in src {
+ io.write(dst, {LOWER[v>>4], LOWER[v&0x0f]}) or_return
+ }
+ return
+}
+
+/*
+Encodes a byte slice into an uppercase hex sequence
- return dst
+*Allocates Using Provided Allocator*
+
+Inputs:
+- src: The `[]byte` to be hex-encoded
+- allocator: (default: context.allocator)
+- loc: The caller location for debugging purposes (default: #caller_location)
+
+Returns:
+- res: The hex-encoded result
+- err: An optional allocator error if one occured, `.None` otherwise
+*/
+encode_upper :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (res: []byte, err: runtime.Allocator_Error) #optional_allocator_error {
+ res, err = make([]byte, len(src) * 2, allocator, loc)
+ #no_bounds_check for i, j := 0, 0; i < len(src); i += 1 {
+ v := src[i]
+ res[j] = UPPER[v>>4]
+ res[j+1] = UPPER[v&0x0f]
+ j += 2
+ }
+ return
}
-encode_into_writer :: proc(dst: io.Writer, src: []byte) -> io.Error {
+/*
+Encodes a byte slice as an uppercase hex sequence into an `io.Writer`
+
+Inputs:
+- dst: The `io.Writer` to encode into
+- src: The `[]byte` to be hex-encoded
+
+Returns:
+- err: An `io.Error` if one occured, `.None` otherwise
+*/
+encode_upper_into_writer :: proc(dst: io.Writer, src: []byte) -> (err: io.Error) {
for v in src {
- io.write(dst, {HEXTABLE[v>>4], HEXTABLE[v&0x0f]}) or_return
+ io.write(dst, {UPPER[v>>4], UPPER[v&0x0f]}) or_return
}
- return nil
+ return
}
-decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) #no_bounds_check {
+/*
+Decodes a hex sequence into a byte slice
+
+*Allocates Using Provided Allocator*
+
+Inputs:
+- dst: The hex sequence decoded into bytes
+- src: The `[]byte` to be hex-decoded
+- allocator: (default: context.allocator)
+- loc: The caller location for debugging purposes (default: #caller_location)
+
+Returns:
+- ok: A bool, `true` if decoding succeeded, `false` otherwise
+*/
+decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) {
if len(src) % 2 == 1 {
return
}
dst = make([]byte, len(src) / 2, allocator, loc)
- for i, j := 0, 1; j < len(src); j += 2 {
+ #no_bounds_check for i, j := 0, 1; j < len(src); j += 2 {
p := src[j-1]
q := src[j]
@@ -43,8 +123,16 @@ decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_locat
return dst, true
}
-// Decodes the given sequence into one byte.
-// Should be called with one byte worth of the source, eg: 0x23 -> '#'.
+/*
+Decodes the first byte in a hex sequence to a byte
+
+Inputs:
+- str: A hex-encoded `string`, e.g. `"0x23"`
+
+Returns:
+- res: The decoded byte, e.g. `'#'`
+- ok: A bool, `true` if decoding succeeded, `false` otherwise
+*/
decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
str := str
if strings.has_prefix(str, "0x") || strings.has_prefix(str, "0X") {
@@ -62,7 +150,7 @@ decode_sequence :: proc(str: string) -> (res: byte, ok: bool) {
}
@(private)
-HEXTABLE := [16]byte {
+LOWER := [16]byte {
'0', '1', '2', '3',
'4', '5', '6', '7',
'8', '9', 'a', 'b',
@@ -70,6 +158,14 @@ HEXTABLE := [16]byte {
}
@(private)
+UPPER := [16]byte {
+ '0', '1', '2', '3',
+ '4', '5', '6', '7',
+ '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F',
+}
+
+@(private)
hex_digit :: proc(char: byte) -> (u8, bool) {
switch char {
case '0' ..= '9': return char - '0', true