Documentation
¶
Overview ¶
Package uhex provides fixed-width, lowercase hexadecimal encoders for unsigned integers and fixed-size byte arrays.
It is intended for hot paths such as trace ID generation, log formatting, and binary protocol work where general-purpose formatting can be unnecessarily expensive. The implementation is deliberately simple: each input byte is mapped through a 256-entry lookup table to its two lowercase hexadecimal characters, which are written with a single 16-bit store.
Compared with generic formatting such as fmt.Sprintf("%x", v), uhex avoids reflection and width handling. Compared with encoding/hex, it focuses on fixed-width values and exposes helpers that write directly into caller-owned arrays.
Output ¶
All encoders produce lowercase hexadecimal.
Integer-based helpers always zero-pad to the full width of the input type:
- Hex64 and Hex64UB produce 16 bytes.
- Hex32 and Hex32UB produce 8 bytes.
- Hex16 and Hex16UB produce 4 bytes.
- Hex8 and Hex8UB produce 2 bytes.
Byte-array helpers encode each input byte in order, two hex characters per byte:
- Hex64B and Hex64BB encode [8]byte values.
- Hex32B and Hex32BB encode [4]byte values.
- Hex16B and Hex16BB encode [2]byte values.
- Hex8B and Hex8BB encode [1]byte values.
Allocation Behavior ¶
The slice-returning helpers (Hex64, Hex32, Hex16, Hex8, Hex64B, Hex32B, Hex16B, and Hex8B) are the most convenient API. Each fills a local array (16, 8, 4, or 2 bytes) and returns a slice over it. Whether that array is allocated on the heap depends on escape analysis at the call site:
- If the returned slice does not escape the caller (for example, it is read and discarded, or only its bytes are consumed), the array stays on the stack and no allocation occurs.
- If the returned slice escapes (it is stored in a longer-lived structure, returned, sent on a channel, or passed to a function the compiler cannot inline), the backing array is heap-allocated, costing one allocation of the array's width.
For code that must never allocate regardless of escape analysis, prefer the buffer-writing helpers that accept a destination array pointer. Hex64UB, Hex32UB, Hex16UB, and Hex8UB write integer encodings into caller-owned buffers. Hex64BB, Hex32BB, Hex16BB, and Hex8BB do the same for fixed-size byte arrays. These never allocate and, for the 32-bit and narrower widths, are small enough to be inlined into the caller.
Performance ¶
Because every width is known at compile time, the encoders are fully unrolled: there are no loops, no length checks, and no argument validation. Each input byte is translated with a single lookup into a 256-entry table and written with one 16-bit store, so the cost scales linearly with the output width and is independent of the input value (there are no data-dependent branches).
Relative to the standard library and general-purpose formatting, for the small fixed widths this package targets:
- Against encoding/hex, the buffer-writing helpers are on the order of two to three times faster and, like encoding/hex.Encode, allocate nothing. Part of the gain on the integer helpers is structural: encoding/hex only encodes byte slices, so encoding an integer with it additionally requires serializing the value into a scratch buffer first, whereas the integer helpers here read the value directly.
- Against fmt.Sprintf("%x", v), the difference is roughly an order of magnitude, and uhex avoids the allocations that reflection-based formatting incurs.
- When a []byte or string result is returned rather than written into a caller-owned buffer, the single heap allocation for that result dominates the total cost, so the advantage over encoding/hex narrows accordingly; the buffer-writing helpers avoid that allocation entirely.
These are relative characteristics, not guarantees; absolute numbers depend on the hardware and compiler. The package ships benchmarks (run with `go test -bench=.`) so the figures can be reproduced on the target platform.
This package is specialized for small, fixed-width values (up to eight bytes). For arbitrary-length or streaming data, or for decoding, use encoding/hex, which is optimized for those cases; uhex offers no advantage there and does not cover them.
Naming ¶
Function suffixes follow this pattern:
- No suffix: encode an unsigned integer and return a []byte.
- UB: encode an unsigned integer into a caller-provided buffer.
- B: encode a fixed-size byte array and return a []byte.
- BB: encode a fixed-size byte array into a caller-provided buffer.
Usage ¶
id := uhex.Hex64(traceID)
sum := uhex.Hex32(checksum)
tag := string(uhex.Hex8(kind))
var dst [16]byte
uhex.Hex64UB(traceID, &dst)
out := dst[:]
src := [8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}
uhex.Hex64BB(src, &dst)
uhex is a good fit when the input width is known in advance and predictable, lowercase, zero-padded hexadecimal output is required.
Index ¶
- func Hex8(n uint8) []byte
- func Hex8B(src [1]byte) []byte
- func Hex8BB(src [1]byte, dst *[2]byte)
- func Hex8UB(n uint8, dst *[2]byte)
- func Hex16(n uint16) []byte
- func Hex16B(src [2]byte) []byte
- func Hex16BB(src [2]byte, dst *[4]byte)
- func Hex16UB(n uint16, dst *[4]byte)
- func Hex32(n uint32) []byte
- func Hex32B(src [4]byte) []byte
- func Hex32BB(src [4]byte, dst *[8]byte)
- func Hex32UB(n uint32, dst *[8]byte)
- func Hex64(n uint64) []byte
- func Hex64B(src [8]byte) []byte
- func Hex64BB(src [8]byte, dst *[16]byte)
- func Hex64UB(n uint64, dst *[16]byte)
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Hex8 ¶
Hex8 returns the zero-padded, lowercase hexadecimal encoding of n as a 2-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex8(uint8(128))
fmt.Println(string(h))
}
Output: 80
func Hex8B ¶
Hex8B returns the lowercase hexadecimal encoding of src as a 2-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex8B([1]byte{0xab})
fmt.Println(string(h))
}
Output: ab
func Hex8BB ¶
Hex8BB writes the lowercase hexadecimal encoding of src into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [2]byte{}
uhex.Hex8BB([1]byte{0xab}, &dst)
fmt.Println(string(dst[:]))
}
Output: ab
func Hex8UB ¶
Hex8UB writes the zero-padded, lowercase hexadecimal encoding of n into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [2]byte{}
uhex.Hex8UB(uint8(128), &dst)
fmt.Println(string(dst[:]))
}
Output: 80
func Hex16 ¶
Hex16 returns the zero-padded, lowercase hexadecimal encoding of n as a 4-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex16(uint16(0xabcd))
fmt.Println(string(h))
}
Output: abcd
func Hex16B ¶
Hex16B returns the lowercase hexadecimal encoding of src as a 4-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex16B([2]byte{0xab, 0xcd})
fmt.Println(string(h))
}
Output: abcd
func Hex16BB ¶
Hex16BB writes the lowercase hexadecimal encoding of src into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [4]byte{}
uhex.Hex16BB([2]byte{0xab, 0xcd}, &dst)
fmt.Println(string(dst[:]))
}
Output: abcd
func Hex16UB ¶
Hex16UB writes the zero-padded, lowercase hexadecimal encoding of n into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [4]byte{}
uhex.Hex16UB(uint16(0xabcd), &dst)
fmt.Println(string(dst[:]))
}
Output: abcd
func Hex32 ¶
Hex32 returns the zero-padded, lowercase hexadecimal encoding of n as an 8-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex32(uint32(0x89abcdef))
fmt.Println(string(h))
}
Output: 89abcdef
func Hex32B ¶
Hex32B returns the lowercase hexadecimal encoding of src as an 8-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex32B([4]byte{0x89, 0xab, 0xcd, 0xef})
fmt.Println(string(h))
}
Output: 89abcdef
func Hex32BB ¶
Hex32BB writes the lowercase hexadecimal encoding of src into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [8]byte{}
uhex.Hex32BB([4]byte{0x89, 0xab, 0xcd, 0xef}, &dst)
fmt.Println(string(dst[:]))
}
Output: 89abcdef
func Hex32UB ¶
Hex32UB writes the zero-padded, lowercase hexadecimal encoding of n into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [8]byte{}
uhex.Hex32UB(uint32(0x89abcdef), &dst)
fmt.Println(string(dst[:]))
}
Output: 89abcdef
func Hex64 ¶
Hex64 returns the zero-padded, lowercase hexadecimal encoding of n as a 16-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex64(uint64(0x0123456789abcdef))
fmt.Println(string(h))
}
Output: 0123456789abcdef
func Hex64B ¶
Hex64B returns the lowercase hexadecimal encoding of src as a 16-byte slice.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
h := uhex.Hex64B([8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef})
fmt.Println(string(h))
}
Output: 0123456789abcdef
func Hex64BB ¶
Hex64BB writes the lowercase hexadecimal encoding of src into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [16]byte{}
uhex.Hex64BB([8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef}, &dst)
fmt.Println(string(dst[:]))
}
Output: 0123456789abcdef
func Hex64UB ¶
Hex64UB writes the zero-padded, lowercase hexadecimal encoding of n into dst.
Example ¶
package main
import (
"fmt"
"github.com/tecnickcom/nurago/pkg/uhex"
)
func main() {
dst := [16]byte{}
uhex.Hex64UB(uint64(0x0123456789abcdef), &dst)
fmt.Println(string(dst[:]))
}
Output: 0123456789abcdef
Types ¶
This section is empty.