/
nv-lang
/
nova
Обзор
Документация
Войти
/
nv-lang
/
nova
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
main
std/src/encoding/hex.nv
96 строк
3 KB
Evgeniy Golovin
merge: comment-hygiene-2 — чистка комментариев std (batch 1-20) + линт-свип 330→13
01 авг 2026, 18:13
01 авг 2026, 18:13
bb8b33d
Код
Авторство
О чём код?
// stdlib/hex.nv — Hex encoding/decoding `[]u8` ↔ `str`. // // Independent implementation. Hex — universal encoding, no copyright. // // API: // Hex.encode(data []u8) -> str // lowercase // Hex.encode_upper(data []u8) -> str // Hex.decode(s str) -> Result[[]u8, ParseHexError] // // Use cases: hash digests (SHA, CRC), binary dumps, debugging, // crypto tokens, file integrity. module encoding.hex /// Errors while parsing a hex string. #stable(since = "0.1") export type ParseHexError enum | OddLength { actual int } | InvalidChar { position int, char char } /// Encode bytes as lowercase hex (e.g. `[0xDE, 0xAD]` → `"dead"`). #stable(since = "0.1") export fn Hex.encode(data []u8) -> str => encode_with(data, false) /// Encode bytes as uppercase hex (`"DEAD"`). #stable(since = "0.1") export fn Hex.encode_upper(data []u8) -> str => encode_with(data, true) fn encode_with(data []u8, upper bool) -> str { consume buf = StringBuilder.new(cap: data.len() * 2) for b in data { ro hi = (b as int) / 16 ro lo = (b as int) % 16 buf.append(digit(hi as u8, upper)) buf.append(digit(lo as u8, upper)) } buf } // Plan 34 Ф.5.2: `int as char` запрещён D54, используем `n.to_char()?`. // n всегда в [0, 15] (вызывается с (b as int) / 16 или % 16), поэтому // code всегда в valid ASCII диапазоне — `char.from` не может вернуть // Err. Fallback `' '` нужен только для exhaustive-match'а. fn digit(n u8, upper bool) -> char { ro code = if n < 10 { '0' as int + n as int } else if upper { 'A' as int + n as int - 10 } else { 'a' as int + n as int - 10 } code.to_char() ?? ' ' } // ────────────────────────────────────────────────────────────────────────── // Decoding // ────────────────────────────────────────────────────────────────────────── /// Decode a hex string into bytes. Case-insensitive. `Err(OddLength)`/`Err(InvalidChar)`. #stable(since = "0.1") export fn Hex.decode(s str) -> Result[[]u8, ParseHexError] { if s.byte_len() % 2 != 0 { return Err(OddLength { actual: s.byte_len() }) } mut out = []u8.new(cap: s.byte_len() / 2) for i in (0..s.byte_len()).step_by(2) { ro hi = digit_value(s, i)? ro lo = digit_value(s, i + 1)? out.push(((hi * 16 + lo) & 0xFF) as u8) } Ok(out) } // Hex digest content is pure ASCII — direct byte access O(1) instead of the // ретрактированный `chars().nth(pos)` O(n) scan (D260-амендмент). fn digit_value(s str, pos int) -> Result[int, ParseHexError] { match s.bytes().get(pos) { Some(b) => { ro n = b as int if n >= 48 && n <= 57 { Ok(n - 48) } else if n >= 97 && n <= 102 { Ok(n - 97 + 10) } else if n >= 65 && n <= 70 { Ok(n - 65 + 10) } else { Err(InvalidChar { position: pos, char: n.to_char() ?? ' ' }) } } None => Err(InvalidChar { position: pos, char: ' ' }) } } // Тесты — см. peer-файл hex_test.nv (module encoding.hex_test).