///|
fn decode_ascii(
payload : Bytes,
scalar : Scalar,
count : Int32,
limits : Limits,
) -> Array[Double] raise NrrdError {
if payload.length() > limits.max_payload_bytes {
raise Limit("ASCII payload budget")
}
let result = []
let token = StringBuilder()
for byte in payload {
let n = byte.to_int()
if n == 32 || n == 9 || n == 10 || n == 13 {
if !token.is_empty() {
if result.length() >= count {
raise Invalid("extra ASCII samples")
}
result.push(scalar.canonical(number(token.to_string())))
token.reset()
}
} else {
if n < 33 || n > 126 {
raise Invalid("non-ASCII payload token")
}
if token.to_string().length() >= 128 {
raise Limit("numeric token length")
}
token.write_char(n.unsafe_to_char())
}
}
if !token.is_empty() {
if result.length() >= count {
raise Invalid("extra ASCII samples")
}
result.push(scalar.canonical(number(token.to_string())))
}
if result.length() != count {
raise Truncated("ASCII sample count")
}
result
}
///|
fn numeric_text(value : Double, scalar : Scalar) -> String {
if value.is_nan() {
return "nan"
}
if value.is_pos_inf() {
return "inf"
}
if value.is_neg_inf() {
return "-inf"
}
if (scalar == F32 || scalar == F64) &&
value == 0.0 &&
(1.0 / value).is_neg_inf() {
return "-0.0"
}
match scalar {
F32 | F64 => value.to_string()
_ => value.to_int64().to_string()
}
}
///|
fn encode_ascii(
data : Array[Double],
scalar : Scalar,
limits : Limits,
) -> Bytes raise NrrdError {
let text = StringBuilder()
let mut size = 0
for value in data {
let token = numeric_text(value, scalar)
if token.length() + 1 > limits.max_payload_bytes - size {
raise Limit("ASCII output budget")
}
text.write_string(token)
text.write_char('\n')
size = size + token.length() + 1
}
@utf8.encode(text.to_string()[:])
}