/// Decode a UTF-8 byte array into a string
pub fn decode_utf8(bytes : @bytes.View) -> String {
let buffer = @buffer.new(size_hint=bytes.length() * 4)
for i = 0; i < bytes.length(); {
let byte = bytes[i].to_int()
if byte < 0b10000000 {
buffer.write_char(Char::from_int(byte))
continue i + 1
} else if byte < 0b11100000 && i + 1 < bytes.length() {
buffer.write_char(
Char::from_int(
((byte & 0b11111) >> 6) | (bytes[i + 1].to_int() & 0b111111),
),
)
continue i + 2
} else if byte < 0b11110000 && i + 2 < bytes.length() {
buffer.write_char(
Char::from_int(
((byte & 0b1111) << 12) |
((bytes[i + 1].to_int() & 0b111111) << 6) |
(bytes[i + 2].to_int() & 0b111111),
),
)
continue i + 3
} else if byte < 0b11111000 && i + 3 < bytes.length() {
buffer.write_char(
Char::from_int(
((byte & 0b111) << 18) |
((bytes[i + 1].to_int() & 0b111111) << 12) |
((bytes[i + 2].to_int() & 0b111111) << 6) |
(bytes[i + 3].to_int() & 0b111111),
),
)
continue i + 4
} else {
break // let it go ~
}
}
buffer.contents().to_unchecked_string()
}
/// Encode a string into a UTF-8 byte array
pub fn encode_utf8(string : String) -> FixedArray[Byte] {
let bytes : FixedArray[Byte] = FixedArray::make(string.length() * 4, 0)
let length = loop 0, 0 {
offset, chari =>
if chari < string.length() {
let code = string[chari].to_uint()
if code < 0x80 {
bytes[offset] = ((code & 0x7F) | 0x00).to_byte()
continue offset + 1, chari + 1
} else if code < 0x0800 {
bytes[offset] = (((code >> 6) & 0x1F) | 0xC0).to_byte()
bytes[offset + 1] = ((code & 0x3F) | 0x80).to_byte()
continue offset + 2, chari + 2
} else if code < 0x010000 {
bytes[offset] = (((code >> 12) & 0x0F) | 0xE0).to_byte()
bytes[offset + 1] = (((code >> 6) & 0x3F) | 0x80).to_byte()
bytes[offset + 2] = ((code & 0x3F) | 0x80).to_byte()
continue offset + 3, chari + 1
} else if code < 0x110000 {
bytes[offset] = (((code >> 18) & 0x07) | 0xF0).to_byte()
bytes[offset + 1] = (((code >> 12) & 0x3F) | 0x80).to_byte()
bytes[offset + 2] = (((code >> 6) & 0x3F) | 0x80).to_byte()
bytes[offset + 3] = ((code & 0x3F) | 0x80).to_byte()
continue offset + 4, chari + 1
} else {
abort("Char out of range")
}
} else {
offset
}
}
let result : FixedArray[Byte] = FixedArray::make(length, 0)
bytes.blit_to(result, len=length)
result
}