3.49. kink/io/INPUT

Companion mod for input vals.

3.49.1. type input

An input is an input port for bytes and bins from an underlying source of bytes such as files.

An input provides sequential forward access to the underlying source of bytes. It does not provide random access operations such as seek.

Operations on an input may cause IO errors.

Input.read_byte(...[$config={}])

Input.read_byte reads a byte from the underlying source.

$config, if specified, must be a fun which takes a conf val. The conf val provides the following methods.

• C.on_present($present_cont) : uses $present_cont as the present cont. If not called, {(:B) [B] } is used as the default present cont.

• C.on_absent($absent_cont) : uses $absent_cont as the absent cont. If not called, { [] } is used as the default absent cont.

• C.on_error($error_cont) : uses $error_cont as the error cont. If not called, the default error cont raises an exception.

Result:

• If read_byte succeeds to read a byte, it tail-calls the present cont with the byte.

• If a byte is unavailable, read_byte tail-calls the absent cont with no args.

• If an IO error occurs, read_byte tail-calls the error cont with the error message.

When the present cont and/or the absent cont are not specified, read_byte returns a maybe vec of a byte:

:BIN.require_from('kink/')
:BIN_INPUT.require_from('kink/io/')

:In <- BIN_INPUT.new(BIN.of(1 2 3))
stdout.print_line(In.read_byte.repr)  # => [1]
stdout.print_line(In.read_byte.repr)  # => [2]
stdout.print_line(In.read_byte.repr)  # => [3]
stdout.print_line(In.read_byte.repr)  # => []
stdout.print_line(In.read_byte.repr)  # => []

Conts can be specified by C.on_present and C.on_absent:

:BIN.require_from('kink/')
:BIN_INPUT.require_from('kink/io/')

:In <- BIN_INPUT.new(BIN.of(1 2 3))
:loop <- {(:Vec)
  In.read_byte{(:C)
    C.on_present{(:Byte) loop(Vec + [Byte]) }
    C.on_absent{ Vec }
  }
}
:Bytes <- loop([])
stdout.print_line(Bytes.repr) # => [1 2 3]

When an IO error occurs, Input.read_byte tail-calls the error cont with an error message.

Example:

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

:In <- FILE.open_to_read('/etc/passwd')
In.close
In.read_byte{(:C)
  C.on_error{(:Msg)
    stderr.print_line(Msg)
  }
}
# => java.io.IOException: Stream Clsoed

CONTROL.try(
  { In.read_byte }
  {(:R) raise('not here') }
  {(:Msg :Traces)
    stderr.print_line(Msg)
  }
)
# => Stream_input.read_byte: java.io.IOException: Stream Closed

Input.read_bin(Max_size ...[$config={}])

Input.read_bin reads bytes till the size reaches Max_size, or reaches the end of the stream.

Precondition:

• Max_size must be a non-negative int num.

• $config, if specified, must be a fun which takes a conf val.

The conf val provides the following methods:

• C.on_present($present_cont) : uses $present_cont as the present cont. If the method is not called, {(:Bin) [Bin] } is used as the default present cont.

• C.on_absent($absent_cont) : uses $absent_cont as the absent cont. If the method is not called, {() [] } is used as the default absent cont.

• C.on_error($error_cont) : uses $error_cont as the error cont. If the method is not called, the default error cont raises an exception when an IO error occurs.

Result:

• If read_bin succeeds to read some bytes, it tail-calls the present cont with a bin of the bytes.

• If no bytes are available, read_bin tail-calls the absent cont with no args.

• If an IO error occurs, read_bin tail-calls the error cont with the error message.

If the present cont and/or the absent cont are not specified, read_bin returns a maybe vec of a bin.

:BIN.require_from('kink/')
:BIN_INPUT.require_from('kink/io/')

:In <- BIN_INPUT.new(BIN.of(1 2 3))
:loop <- {(:Vec)
  In.read_bin(2).for_maybe(
    {(:Bin) loop(Vec + [Bin]) }
    { Vec }
  )
}
:Result <- loop([])
stdout.print_line(Result.repr)  # => [BIN.of(0x01 0x02) BIN.of(0x03)]

The present cont and the absent cont can be specified by C.on_present and C.on_absent.

:BIN.require_from('kink/')
:BIN_INPUT.require_from('kink/io/')

:In <- BIN_INPUT.new(BIN.of(1 2 3))
:loop <- {(:Vec)
  In.read_bin(2){(:C)
    C.on_present{(:Bin) loop(Vec + [Bin]) }
    C.on_absent{ Vec }
  }
}
:Result <- loop([])
stdout.print_line(Result.repr)  # => [BIN.of(0x01 0x02) BIN.of(0x03)]

When an error occurs, Input.read_bin tail-calls $on_error with an error message, or raises an exception if $on_error is not given.

Example:

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

:In <- FILE.open_to_read('/etc/passwd')
In.close
In.read_bin(10){(:C)
  C.on_error{(:Msg)
    stderr.print_line(Msg)
  }
}
# => java.io.IOException: Stream Clsoed

CONTROL.try(
  { In.read_bin(10) }
  {(:R) raise('not here') }
  {(:Msg :Traces)
    stderr.print_line(Msg)
  }
)
# => Stream_input.read_bin: java.io.IOException: Stream Closed

Input.read_all(...[$config={}])

Input.read_all reads all the remaining bytes.

Precondition:

• $config, if specified, must be a fun which takes a conf val.

The conf val provides the following methods:

• C.on_success($success_cont) : uses $success_cont as the success cont. If the method is not called, uses CORE.identity as the default success cont.

• C.on_error($error_cont) : uses $error_cont as the error cont. If the method is not called, the default error cont raises an exception when an IO error occcurs.

Result:

• If read_all succeeds to read some bytes, it tail-calls the success cont with a bin of the bytes.

• If there is no remaining bytes, read_all tail-calls the success cont with an empty bin.

• If an IO error occurs, read_all tail-calls the error cont with an error message.

Example:

:BIN.require_from('kink/')
:BIN_INPUT.require_from('kink/io/')

:In <- BIN_INPUT.new(BIN.of(1 2 3))
stdout.print_line(In.read_all.repr)  # => BIN.of(0x01 0x02 0x03)
stdout.print_line(In.read_all.repr)  # => BIN.of()
stdout.print_line(In.read_all.repr)  # => BIN.of()

Example:

:FILE.require_from('kink/io/')
:CONTROL.require_from('kink/')

:In <- FILE.open_to_read('/etc/passwd')
In.close
In.read_all{(:C)
  C.on_error{(:Msg) stderr.print_line(Msg) }
}
# => java.io.IOException: Stream Clsoed

CONTROL.try(
  { In.read_all }
  {(:R) raise('not here') }
  {(:Msg :Traces)
    stderr.print_line(Msg)
  }
)
# => Stream_input.read_all: java.io.IOException: Stream Closed

Input.close(...[$config])

Input.close closes the underlying source of bytes.

Precondition:

• $config, if specified, must be a fun which takes a conf val.

The conf val provides the following methods.

• C.on_success($success_cont) : uses $success_cont as the success cont. If not called, {} is used as the default success cont.

• C.on_error($error_cont) : uses $error_cont as the error cont. If not called, the default error cont raises an exception when an IO error occurs.

Result:

• When Input.close succeeds to close the source of bytes, it tail-calls the success cont with no args.

• When an IO errro occurs, Input.close tail-calls the errro cont with the errror message.

3.49.2. INPUT.is?(Val)

INPUT.is? returns whether the Val is an input.