///|
/// Offsets are UTF-16 indices for hex text and byte offsets for binary input.
pub(all) struct Diagnostic {
offset : Int
code : String
message : String
} derive(Debug, Eq)
///|
pub extend Diagnostic with @debug.Debug::{to_repr}
///|
pub extend Diagnostic with Eq::{equal, not_equal}
///|
fn diagnostic(offset : Int, code : String, message : String) -> Diagnostic {
{ offset, code, message, }
}
///|
/// Accepts hexadecimal byte pairs, optionally separated by ASCII whitespace.
/// Whitespace inside a byte pair, 0x prefixes and punctuation are rejected.
pub fn parse_hex(text : String) -> Result[Bytes, Diagnostic] {
let bytes : Array[Byte] = []
let mut high = -1
let mut high_offset = 0
for i = 0; i < text.length(); i = i + 1 {
let c = text[i].to_int()
if c == 32 || c == 9 || c == 10 || c == 13 {
if high >= 0 {
return Err(diagnostic(i, "split_byte", "Whitespace splits a byte pair"))
}
continue
}
let digit = if c >= 48 && c <= 57 {
c - 48
} else if c >= 65 && c <= 70 {
c - 55
} else if c >= 97 && c <= 102 {
c - 87
} else {
return Err(diagnostic(i, "invalid_hex", "Expected a hexadecimal digit"))
}
if high < 0 {
high = digit
high_offset = i
} else {
bytes.push((high * 16 + digit).to_byte())
high = -1
}
}
if high >= 0 {
Err(diagnostic(high_offset, "odd_hex", "Byte pair has only one digit"))
} else {
Ok(Bytes::from_array(bytes[:]))
}
}