///|
struct Buffer {
mut buf : FixedArray[Byte]
mut len : Int
}
///|
pub fn Buffer::new(capacity? : Int = 0) -> Buffer {
let cap = if capacity < 0 { 0 } else { capacity }
Buffer::{ buf: FixedArray::make(cap, 0x00), len: 0 }
}
///|
pub impl Default for Buffer with default() {
Buffer::new()
}
///|
pub fn buffer(capacity? : Int = 0) -> Buffer {
Buffer::new(capacity~)
}
///|
pub fn Buffer::length(self : Buffer) -> Int {
self.len
}
///|
pub fn Buffer::capacity(self : Buffer) -> Int {
self.buf.length()
}
///|
fn Buffer::grow(self : Buffer, by~ : Int) -> Unit {
let new_len = self.len + by
let mut cap = self.buf.length()
if new_len <= cap {
return
}
if cap == 0 {
cap = 16
}
while cap < new_len {
cap *= 2
}
let new_buf : FixedArray[Byte] = FixedArray::make(cap, 0x00)
new_buf.unsafe_blit(0, self.buf, 0, self.len)
self.buf = new_buf
}
///|
fn Buffer::write_byte_unchecked(self : Buffer, b : Byte) -> Unit {
self.grow(by=1)
self.buf[self.len] = b
self.len = self.len + 1
}
///|
pub fn Buffer::write_byte(self : Buffer, b : Byte) -> Unit raise Malformed {
self.grow(by=1)
self.buf[self.len] = b
self.check(self.len + 1)
self.len = self.len + 1
}
///|
fn Buffer::check(self : Buffer, length : Int) -> Unit raise Malformed {
match self.buf.unsafe_reinterpret_as_bytes()[:length] {
[.., 0x00..=0x7F] => ()
[.., 0xC2..=0xDF] => ()
[.., 0xC2..=0xDF, 0x80..=0xBF] => ()
[.., 0xE0] => ()
[.., 0xE0, 0xA0..=0xBF] => ()
[.., 0xE0, 0xA0..=0xBF, 0x80..=0xBF] => ()
[.. prev, 0xED, 0xA0..=0xBF, 0x80..=0xBF, 0xED, 0xB0..=0xBF, 0x80..=0xBF] =>
raise Malformed(prev.length())
[.., 0xE1..=0xEF] => ()
[.., 0xE1..=0xEF, 0x80..=0xBF] => ()
[.., 0xE1..=0xEF, 0x80..=0xBF, 0x80..=0xBF] => ()
[.., 0xF0] => ()
[.., 0xF0, 0x90..=0xBf] => ()
[.., 0xF0, 0x90..=0xBf, 0x80..=0xBF] => ()
[.., 0xF0, 0x90..=0xBf, 0x80..=0xBF, 0x80..=0xBF] => ()
[.., 0xF1..=0xF3] => ()
[.., 0xF1..=0xF3, 0x80..=0xBF] => ()
[.., 0xF1..=0xF3, 0x80..=0xBF, 0x80..=0xBF] => ()
[.., 0xF1..=0xF3, 0x80..=0xBF, 0x80..=0xBF, 0x80..=0xBF] => ()
[.., 0xF4] => ()
[.., 0xF4, 0x80..=0x8F] => ()
[.., 0xF4, 0x80..=0x8F, 0x80..=0xBF] => ()
[.., 0xF4, 0x80..=0x8F, 0x80..=0xBF, 0x80..=0xBF] => ()
[..] as view => raise Malformed(view.start_offset())
}
}
///|
pub fn Buffer::write_bytesview(
self : Buffer,
bytesview : BytesView,
) -> Unit raise Malformed {
let n = bytesview.length()
let len = self.len
self.grow(by=n)
self.buf.blit_from_bytes(len, bytesview.data(), bytesview.start_offset(), n)
self.check(len + n)
self.len = self.len + 1
}
///|
pub fn Buffer::write_bytes(
self : Buffer,
bytes : Bytes,
) -> Unit raise Malformed {
let n = bytes.length()
let len = self.len
self.grow(by=n)
self.buf.blit_from_bytes(len, bytes, 0, n)
self.check(len + n)
self.len = len + n
}
///|
pub fn Buffer::to_wtf8(self : Buffer) -> Wtf8 {
let buf = self.buf
let len = self.len
self.len = 0
if len < buf.length() {
let bytes : FixedArray[Byte] = FixedArray::make(len, 0)
bytes.unsafe_blit(0, buf, 0, len)
bytes.unsafe_reinterpret_as_bytes()
} else {
buf.unsafe_reinterpret_as_bytes()
}
}
///|
pub fn Buffer::write_codepoint(
self : Buffer,
codepoint : @codepoint.CodePoint,
) -> Unit {
let cp = codepoint.to_int()
if cp <= 0x7F {
self.write_byte_unchecked(cp.to_byte())
} else if cp <= 0x7FF {
self.write_byte_unchecked((0xC0 | ((cp >> 6) & 0x1F)).to_byte())
self.write_byte_unchecked((0x80 | (cp & 0x3F)).to_byte())
} else if cp <= 0xFFFF {
self.write_byte_unchecked((0xE0 | ((cp >> 12) & 0x0F)).to_byte())
self.write_byte_unchecked((0x80 | ((cp >> 6) & 0x3F)).to_byte())
self.write_byte_unchecked((0x80 | (cp & 0x3F)).to_byte())
} else {
self.write_byte_unchecked((0xF0 | ((cp >> 18) & 0x07)).to_byte())
self.write_byte_unchecked((0x80 | ((cp >> 12) & 0x3F)).to_byte())
self.write_byte_unchecked((0x80 | ((cp >> 6) & 0x3F)).to_byte())
self.write_byte_unchecked((0x80 | (cp & 0x3F)).to_byte())
}
}