Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+99
View File
@@ -0,0 +1,99 @@
module hex
const hex_digits = '0123456789abcdef'
const hex_digits_upper = '0123456789ABCDEF'
// EncodeParams configures optional output formatting for encode.
//
// If `uppercase` is set, `encode` emits `A-F` instead of `a-f`.
// If `with_prefix` is non-empty, `encode` prepends that exact string.
@[params]
pub struct EncodeParams {
pub mut:
uppercase bool
with_prefix string
}
// decode converts a hex string into an array of bytes.
// The expected input format is 2 ASCII characters for each output byte.
// If the provided string length is not a multiple of 2, the first digit is
// decoded as if an implicit `0` preceded it. An optional `0x` or `0X` prefix
// is accepted.
@[direct_array_access]
pub fn decode(s string) ![]u8 {
if s.len == 0 {
return []u8{}
}
mut offset := 0
mut hex_bytes := if s.len >= 2 {
if s[0] == `0` && (s[1] == `x` || s[1] == `X`) {
offset = 2
s[2..].bytes()
} else {
s.bytes()
}
} else {
s.bytes()
}
if hex_bytes.len == 0 {
return []u8{}
}
mut bytes := []u8{cap: (hex_bytes.len + 1) >> 1}
mut start := 0
if hex_bytes.len & 1 == 1 {
bytes << char2nibble(hex_bytes[0], offset)!
start = 1
}
for i := start; i < hex_bytes.len; i += 2 {
n1 := char2nibble(hex_bytes[i], offset + i)!
n0 := char2nibble(hex_bytes[i + 1], offset + i + 1)!
bytes << (n1 << 4) | n0
}
return bytes
}
// encode converts an array of bytes into a string of ASCII hex bytes. The
// output will always be a string whose length will be a multiple of 2.
// If `EncodeParams.uppercase` is set, the output hex characters are emitted in
// uppercase.
// If `EncodeParams.with_prefix` is non-empty, the output string is prefixed
// with the provided string.
@[direct_array_access]
pub fn encode(bytes []u8, params EncodeParams) string {
if bytes.len == 0 {
return ''
}
mut res := []u8{}
if params.with_prefix != '' {
res << params.with_prefix.bytes()
}
for _, b in bytes {
res << nibble2char(b >> 4, params)
res << nibble2char(b & 0xf, params)
}
return res.bytestr()
}
// nibble2char converts a 4-bit hex value to its ASCII character
@[inline]
fn nibble2char(nibble u8, params EncodeParams) u8 {
if params.uppercase {
return hex_digits_upper[nibble]
}
return hex_digits[nibble]
}
// char2nibble converts an ASCII hex character to its hex value
@[inline]
fn char2nibble(b u8, index int) !u8 {
match b {
`0`...`9` { return b - u8(`0`) }
`A`...`F` { return b - u8(`A`) + 10 }
`a`...`f` { return b - u8(`a`) + 10 }
else { return error('invalid hex char ${b.ascii_str()} at index ${index}') }
}
}
+75
View File
@@ -0,0 +1,75 @@
module hex
fn test_decode() {
assert decode('')! == []
assert decode('0')! == [u8(0x0)]
assert decode('f')! == [u8(0xf)]
assert decode('0f')! == [u8(0x0f)]
assert decode('ff')! == [u8(0xff)]
assert decode('123')! == [u8(0x1), 0x23]
assert decode('1234')! == [u8(0x12), 0x34]
assert decode('12345')! == [u8(0x1), 0x23, 0x45]
assert decode('0123456789abcdef')! == [u8(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
assert decode('123456789ABCDEF')! == [u8(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
}
fn test_decode_fails() ! {
if x := decode('foo') {
return error('expected decode to fail, got ${x}')
}
if x := decode('g') {
return error('expected decode to fail, got ${x}')
}
if x := decode('000000000g') {
return error('expected decode to fail, got ${x}')
}
if x := decode('_') {
return error('expected decode to fail, got ${x}')
}
if x := decode('!') {
return error('expected decode to fail, got ${x}')
}
}
fn test_encode() {
assert encode(decode('')!) == ''
assert encode(decode('0')!) == '00'
assert encode(decode('f')!) == '0f'
assert encode(decode('0f')!) == '0f'
assert encode(decode('ff')!) == 'ff'
assert encode(decode('123')!) == '0123'
assert encode(decode('1234')!) == '1234'
assert encode(decode('12345')!) == '012345'
assert encode(decode('abcdef')!) == 'abcdef'
assert encode(decode('ABCDEF')!) == 'abcdef'
}
fn test_encode_params() {
assert encode([u8(0xab), 0xcd], uppercase: true) == 'ABCD'
assert encode([u8(0xab), 0xcd], with_prefix: '0x') == '0xabcd'
assert encode([u8(0xab), 0xcd], uppercase: true, with_prefix: '0X') == '0XABCD'
assert encode([u8(0xab), 0xcd], with_prefix: 'hex:') == 'hex:abcd'
}
fn test_decode_0x() {
assert decode('0x') or { []u8{} } == []u8{}
assert decode('0x0')! == [u8(0x0)]
assert decode('0X1234')! == [u8(0x12), 0x34]
assert decode('0x12345')! == [u8(0x1), 0x23, 0x45]
assert decode('0x0123456789abcdef')! == [u8(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
assert decode('0X123456789ABCDEF')! == [u8(0x01), 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]
}
fn test_decode_error_indexes() {
decode('g') or {
assert err.msg() == 'invalid hex char g at index 0'
return
}
assert false
decode('0xg') or {
assert err.msg() == 'invalid hex char g at index 2'
return
}
assert false
}