///|
struct Buffer {
mut b : Slice[Byte]
// off represent the current read/write position in the buffer.
// It is recommended to use the buffer as a reader or writer
// but not both at the same time.
mut off : Int
}
///|
/// Buffer::new creates a new empty Buffer with an optional size hint.
/// The size hint is used to preallocate memory for the buffer, which can
/// improve performance when the size of the data to be written is known in advance.
pub fn Buffer::new(size_hint? : Int = 0) -> Buffer {
let b = Slice::new(Array::make(size_hint, b'\x00'), start=0, end=0)
{ b, off: 0 }
}
///|
let _trait4 : &Reader = Buffer::new()
///|
let _trait5 : &Writer = Buffer::new()
///|
pub fn Buffer::from_slice(s : Slice[Byte]) -> Buffer {
let b = Slice::new(s.to_bytes().to_array())
{ b, off: 0 }
}
///|
pub fn Buffer::from_bytes(b : Bytes) -> Buffer {
let buf = Slice::new(b.to_array())
{ b: buf, off: 0 }
}
///|
/// `Buffer::from_string` converts the MoonBit UTF-16 String to UTF-8
/// and creates a Buffer from the bytes.
pub fn Buffer::from_string(s : String) -> Buffer {
let b = @base64.str2bytes(s)
let buf = Slice::new(b.to_array())
{ b: buf, off: 0 }
}
///|
pub fn Buffer::reset(self : Buffer, size_hint? : Int = 0) -> Unit {
self.b = Slice::new(Array::make(size_hint, b'\x00'), start=0, end=0)
self.off = 0
}
///|
pub impl Writer for Buffer with fn write(self, buf) {
let blen = self.b.length()
let buflen = buf.length()
self.b = Slice::new(
Array::makei(blen + buflen, fn(i) {
if i < blen {
self.b[i]
} else {
buf.buf[buf.start + i - blen]
}
}),
)
(buflen, None)
}
///|
pub fn Buffer::write_bytes(self : Buffer, buf : Bytes) -> (Int, IOError?) {
self.write(Slice::new(buf.to_array()))
}
///|
pub fn Buffer::write_byte(self : Buffer, b : Byte) -> (Int, IOError?) {
self.write(Slice::new([b]))
}
///|
/// `write_string` converts the MoonBit UTF-16 String to UTF-8 and
/// writes the bytes to the buffer.
pub fn Buffer::write_string(self : Buffer, s : String) -> (Int, IOError?) {
let b = @base64.str2bytes(s)
self.write_bytes(b)
}
///|
pub impl Reader for Buffer with fn read(self, buf) {
let remaining = self.b.length() - self.off
if remaining <= 0 || buf.length() == 0 {
return (0, Some(eof))
}
let n = minimum(remaining, buf.length())
Array::unsafe_blit(buf.buf, buf.start, self.b.buf, self.off, n)
self.off += n
(n, None)
}
///|
pub impl ByteReader for Buffer with fn read_byte(self) {
let remaining = self.b.length() - self.off
if remaining <= 0 {
return (0, Some(eof))
}
let b = self.b[self.off]
self.off += 1
(b, None)
}
///|
pub fn Buffer::read_from(self : Buffer, r : &Reader) -> (Int64, IOError?) {
copy(self, r)
}
///|
fn minimum(a : Int, b : Int) -> Int {
if a < b {
a
} else {
b
}
}
///|
pub fn Buffer::to_bytes(self : Buffer) -> Bytes {
Bytes::from_array(self.b.buf)
}
///|
pub impl Show for Buffer with fn to_string(self) {
@base64.bytes2str(Bytes::from_array(self.b.buf))
}
///|
pub impl Show for Buffer with fn output(self, logger) {
logger.write_string(self.to_string())
}
///|
pub impl Eq for Buffer with fn equal(self, other) {
if self.b.length() != other.b.length() {
return false
}
for i in 0.. Slice[Byte] {
Slice::new(self.b.buf)
}
///|
pub fn Buffer::length(self : Buffer) -> Int {
self.b.length()
}
///|
pub fn Buffer::op_get(self : Buffer, index : Int) -> Byte {
self.b[index]
}
///|
pub fn Buffer::substring(self : Buffer, start? : Int = 0, end? : Int) -> String {
let end = match end {
None => self.b.length()
Some(x) => x
}
guard start >= 0 && start <= end && end <= self.b.length() else {
abort(
"Buffer::substring(start=\{start}, end=\{end}) out of bounds for length=\{self.b.length()})",
)
}
let bytes = Bytes::from_iter(self.b[start:end].iter())
@base64.bytes2str(bytes)
}
///|
test "Buffer::substring" {
let buf = Buffer::new()
buf.write_string("hello world") |> ignore()
inspect(buf.substring(), content="hello world")
inspect(buf.substring(start=6), content="world")
inspect(buf.substring(start=0, end=5), content="hello")
}
///|
test "panic Buffer::substring/out-of-bounds 1" {
let buf = Buffer::from_string("hello world")
ignore(buf.substring(start=-1))
}
///|
test "panic Buffer::substring/out-of-bounds 2" {
let buf = Buffer::from_string("hello world")
ignore(buf.substring(start=12))
}
///|
test "panic Buffer::substring/out-of-bounds 3" {
let buf = Buffer::from_string("hello world")
ignore(buf.substring(start=0, end=12))
}
///|
test "panic Buffer::substring/out-of-bounds 4" {
let buf = Buffer::from_string("hello world")
ignore(buf.substring(start=6, end=5))
}
///|
test "Buffer::substring/empty" {
let buf = Buffer::new()
inspect(buf.substring(), content="")
inspect(buf.substring(start=0, end=0), content="")
}