std.io.Buffer
class pub Buffer[T: Bytes]
An in-memory buffer that supports reads and seeks.
Buffer
supports any Bytes
type, such as String
and ByteArray
.
The Buffer
type is useful when a method operates on a Read
type (e.g. a
ReadOnlyFile
), and you want to test that method without performing actual IO
operations. For example:
import std.io (Buffer, Read)
fn read_string[T: Read + mut](reader: T) -> String {
let bytes = ByteArray.new
reader.read_all(bytes)
bytes.into_string
}
let reader = Buffer.new('hello')
read_string(reader) # => "hello"
Static methods
new
Show source codeHide source code
fn pub static new(bytes: T) -> Buffer[T] {
Buffer(bytes: bytes, offset: 0)
}
fn pub static new(bytes: T) -> Buffer[T]
Returns a new Buffer
wrapping the given Bytes
.
Instance methods
bytes
Show source codeHide source code
fn pub mut bytes -> Stream[Result[Int, Error]] {
Stream.new(fn move {
match read_byte {
case Ok(Some(num)) -> Option.Some(Result.Ok(num))
case Ok(None) -> Option.None
case Error(err) -> Option.Some(Result.Error(err))
}
})
}
fn pub mut bytes -> Stream[Result[Int, Error]]
Returns an iterator that yields the bytes in self
.
Each byte is wrapped in a Result
, as reading may fail.
Examples
import std.fs.file (ReadOnlyFile)
import std.io (BufferedReader)
let file = ReadOnlyFile.new('README.md').get
let reader = BufferedReader.new(file)
reader.bytes.next # => Option.Some(Result.Ok(35))
peek
Show source codeHide source code
fn pub mut peek -> Result[Option[Int], Error] {
if @offset < @bytes.size {
Result.Ok(Option.Some(@bytes.byte(@offset)))
} else {
Result.Ok(Option.None)
}
}
fn pub mut peek -> Result[Option[Int], Error]
Reads the current byte from the buffer, without consuming it from the underlying buffer.
If a byte is read, Ok(Some(n))
is returned where n
is the byte. A
Ok(None)
indicates the end of the input.
Examples
import std.io (Buffer, BufferedReader)
let buffer = Buffer.new('hello')
let reader = BufferedReader.new(buffer)
reader.peek # => Result.Ok(Option.Some(104))
reader.peek # => Result.Ok(Option.Some(104))
read
Show source codeHide source code
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Never] {
Result.Ok(read_buffer(into, size))
}
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Never]
Reads up to size
bytes from self
into the given ByteArray
, returning
the number of bytes read.
The into
argument is the ByteArray
to read the bytes into. The capacity
of this ByteArray
is increased automatically if necessary.
The size
argument specifies how many bytes are to be read.
The return value is the number of bytes read.
The number of bytes read may be less than size
. This can happen for
different reasons, such as when all input is consumed or not enough data is
available (yet).
read_all
Show source codeHide source code
fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, Error] {
let mut total = 0
let mut read_size = INITIAL_READ_ALL_SIZE
loop {
match read(into: bytes, size: read_size) {
case Ok(0) -> return Result.Ok(total)
case Ok(n) -> {
total += n
# To reduce the number of calls to `Reader.read` when there's lots of
# input to consume, we increase the read size if deemed beneficial.
if read_size < MAX_READ_ALL_SIZE and n == read_size { read_size *= 2 }
}
case Error(e) -> throw e
}
}
}
fn pub mut read_all(bytes: mut ByteArray) -> Result[Int, Error]
Reads from self
into the given ByteArray
, returning when all input is
consumed.
The return value is the number of bytes read.
Errors
This method returns an Error
if the underlying call to Read.read
returns
an Error
.
read_byte
Show source codeHide source code
fn pub mut read_byte -> Result[Option[Int], Never] {
if @offset < @bytes.size {
Result.Ok(Option.Some(@bytes.byte(@offset := @offset + 1)))
} else {
Result.Ok(Option.None)
}
}
fn pub mut read_byte -> Result[Option[Int], Never]
Read and return a single byte.
If a byte is read, Ok(Some(n))
is returned where n
is the byte. A
Ok(None)
indicates the end of the input.
Examples
import std.io (Buffer, BufferedReader)
let buffer = Buffer.new('hello')
let reader = BufferedReader.new(buffer)
reader.read_byte # => Result.Ok(Option.Some(104))
reader.read_byte # => Result.Ok(Option.Some(101))
read_exact
Show source codeHide source code
fn pub mut read_exact(into: mut ByteArray, size: Int) -> Result[Nil, Error] {
let mut pending = size
while pending > 0 {
match read(into, pending) {
case Ok(0) if pending > 0 -> throw Error.EndOfInput
case Ok(n) -> pending -= n
case Error(e) -> throw e
}
}
Result.Ok(nil)
}
fn pub mut read_exact(into: mut ByteArray, size: Int) -> Result[Nil, Error]
Reads exactly size
bytes into into
.
Whereas Read.read
might return early if fewer bytes are available in the
input stream, Read.read_exact
continues reading until the desired amount
of bytes is read.
Errors
If the end of the input stream is encountered before filling the buffer, an
Error.EndOfInput
error is returned.
If an error is returned, no assumption can be made about the state of the
into
buffer, i.e. there's no guarantee data read so far is in the buffer
in the event of an error.
read_line
Show source codeHide source code
fn pub mut read_line(
into: mut ByteArray,
inclusive: Bool,
) -> Result[Int, Error] {
read_until(byte: 0xA, into: into, inclusive: inclusive)
}
fn pub mut read_line(into: mut ByteArray, inclusive: Bool) -> Result[Int, Error]
Read bytes into into
up to and including the newline byte (0xA aka
"\n"
).
The inclusive
argument specifies if the newline should also be read into
the ByteArray
, or if it should be discarded.
Upon success, the return value is Ok(n)
where n
is the number of bytes
read from the input stream. If inclusive
is set to false
, n
still
accounts for the newline. That is, if the input is ab\n
, then the returned
size is 3 bytes.
Examples
Reading until and including the end of a line:
import std.io (Buffer, BufferedReader)
let reader = BufferedReader.new(Buffer.new('hello\nworld'))
let bytes = ByteArray.new
reader.read_line(into: bytes, inclusive: true) # => Result.Ok(6)
bytes.to_string # => 'hello\n'
Excluding the newline from the buffer:
import std.io (Buffer, BufferedReader)
let reader = BufferedReader.new(Buffer.new('hello\nworld'))
let bytes = ByteArray.new
reader.read_line(into: bytes, inclusive: false) # => Result.Ok(6)
bytes.to_string # => 'hello'
read_until
Show source codeHide source code
fn pub mut read_until(
byte: Int,
into: mut ByteArray,
inclusive: Bool,
) -> Result[Int, Error] {
let mut total = 0
loop {
match try read_byte {
case Some(val) if byte == val -> {
if inclusive { into.push(val) }
total += 1
break
}
case Some(val) -> {
total += 1
into.push(val)
}
case _ -> break
}
}
Result.Ok(total)
}
fn pub mut read_until(byte: Int, into: mut ByteArray, inclusive: Bool) -> Result[Int, Error]
Read bytes into into
up to and including the byte specified in the byte
argument.
The inclusive
argument specifies if the byte
value should also be read
into the ByteArray
, or if it should be discarded.
Upon success, the return value is Ok(n)
where n
is the number of bytes
read from the input stream. If inclusive
is set to false
, n
still
accounts for the terminal byte. That is, if the input is abc
and the
terminal byte is c
, then the returned size is 3 bytes.
Examples
Reading until and including a given byte:
import std.io (Buffer, BufferedReader)
let reader = BufferedReader.new(Buffer.new('hello\nworld'))
let bytes = ByteArray.new
reader.read_until(byte: 0xA, into: bytes, inclusive: true) # => Result.Ok(6)
bytes.to_string # => 'hello\n'
Excluding the byte from the buffer:
import std.io (Buffer, BufferedReader)
let reader = BufferedReader.new(Buffer.new('hello\nworld'))
let bytes = ByteArray.new
reader.read_until(byte: 0xA, into: bytes, inclusive: false) # => Result.Ok(6)
bytes.to_string # => 'hello'
seek
Show source codeHide source code
fn pub mut seek(position: Int) -> Result[Int, Never] {
if position < 0 {
@offset = @bytes.size + position
} else {
@offset = position
}
Result.Ok(@offset)
}
fn pub mut seek(position: Int) -> Result[Int, Never]
Seeks to the given byte offset, returning the new offset.
If position
is negative, seeking is performed in reverse order relative to
the end.
Implemented traits
BufferedRead
impl BufferedRead for Buffer
Read
impl Read for Buffer
Seek
impl Seek for Buffer