Search results

There are no results.

std.io.BufferedReader

class pub BufferedReader[T: mut + Read]

A type for performing buffered reads from a Read type.

Using a Read type directly can be inefficient, as many calls to Read.read may involve many system calls. BufferedReader wraps a Read and buffers data into an internal buffer, reducing the total amount of system calls, at the cost of needing to maintain an in-memory buffer.

Static methods

new

Show source code
Hide source code
fn pub static new(reader: T) -> BufferedReader[T] {
  with_capacity(reader, READ_BUFFER_SIZE)
}
fn pub static new(reader: T: mut) -> BufferedReader[T: mut]

Returns a new buffered reader that wraps the given Read type, using the default buffer size.

with_capacity

Show source code
Hide source code
fn pub static with_capacity(reader: T, size: Int) -> BufferedReader[T] {
  if size <= 0 { invalid_buffer_size(size) }

  BufferedReader(
    reader: reader,
    buffer: ByteArray.new,
    capacity: size,
    offset: 0,
  )
}
fn pub static with_capacity(reader: T: mut, size: Int) -> BufferedReader[T: mut]

Returns a new buffered reader that wraps the given Read type, using the specified buffer size.

The reader argument can be any Read type, provided it allows mutation (e.g. a ref Reader isn't valid).

Instance methods

bytes

Show source code
Hide 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 code
Hide source code
fn pub mut peek -> Result[Option[Int], Error] {
  match try fill_buffer {
    case 0 -> Result.Ok(Option.None)
    case _ -> Result.Ok(Option.Some(@buffer.get(@offset)))
  }
}
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 code
Hide source code
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error] {
  let mut total = 0

  # If the read size is larger than our buffer, there's no point in buffering
  # as we can just read all data at once (of course taking account the bytes
  # still in the buffer).
  if size > @capacity {
    if @offset < @capacity and @buffer.size > 0 {
      total += read_buffer(into, size)
    }

    return match size - total {
      case 0 -> Result.Ok(total)
      case n -> Result.Ok(total + try @reader.read(into, size: n))
    }
  }

  while total < size {
    if (try fill_buffer) == 0 { break }

    match read_buffer(into, size - total) {
      case 0 -> break
      case n -> total += n
    }
  }

  Result.Ok(total)
}
fn pub mut read(into: mut ByteArray, size: Int) -> Result[Int, Error]

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 code
Hide 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 code
Hide source code
fn pub mut read_byte -> Result[Option[Int], Error] {
  match try fill_buffer {
    case 0 -> Result.Ok(Option.None)
    case _ -> Result.Ok(Option.Some(@buffer.get(@offset := @offset + 1)))
  }
}
fn pub mut read_byte -> Result[Option[Int], Error]

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 code
Hide 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 code
Hide 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 code
Hide 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'

Implemented traits

std.io.

BufferedRead

impl BufferedRead for BufferedReader
std.io.

Read

impl Read for BufferedReader