6.55. kink/io/INPUT

Companion mod for input vals.

6.55.1. type input

`input` is an input port of bytes from the underlying source such as files.

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

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

`read` reads bytes from the stream. `read` blocks until one or more bytes are read, the end-of-file is detected, or an IO error occurs.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_eof($eof): default = fun which raises an exception

• C.on_error($error): default = fun which raises an exception

If one or more bytes are read, `read` tail-calls $success with a `bin` val of the bytes. The size of the `bin` val does not exceed `Max_size`.

If the end-of-file is detected, `read` tail-calls $eof with no arg.

If an IO error occurs, `read` tail-calls $error with an `exception`.

Preconditions

`Max_size` must be an int `num` which is bigger than or equal to 1.

$success must be a fun which takes a `bin`.

$eof must be a fun which takes no arg.

$error must be a fun which takes an `exception`.

Example

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

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

Example: IO error

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

:In <- FILE.open_to_read('/etc/passwd')
In.close
In.read(10){(:C)
  C.on_error{(:Exc)
    stderr.print_line(Exc.message)
  }
}
# => already closed

In.read(10)
# Output:
#   -- main exception
#   [..root..]
#   {..call by host..}
#   ,,,
#   {builtin:kink-mods/kink/EXCEPTION.kn L117 C13 current_traces} { TRACE.-->current_traces }
#   already closed

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

`read_all` reads bytes until it reaches the end-of-file, or an IO error occurs.

Config methods:

• C.on_success($success): default = VAL.identity

• C.on_error($error): default = {(:Exc) Exc.raise }

If one or more bytes are read with no IO error, `read_all` tail-calls $success with a `bin` of the bytes.

If no byte is read, `read_all` tail-calls $success with an empty `bin`.

If an IO error occurs, `read_all` tail-calls $error with an `exception`.

Precondition

$success must be a fun which takes a `bin`

$error must be a fun which takes an `exception`

Example

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

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

See also

INPUT.mixin: it provides a generic implementation of `read_all`.

6.55.1.3. Input.close(...[$config={}])

`close` closes the resource of the underlying source of bytes.

Config methods:

• C.on_success($success): default = {}

• C.on_error($error): default = a fun which raises an exception

If the resource is closed with no error, `close` tail-calls $success with no arg.

If an IO error occurs, `close` tail-calls $error with an `exception`.

Preconditions

$success must be a fun which takes no arg

$error must be a fun which takes an `exception`

6.55.2. INPUT.is?(Val)

`is?` returns whether `Val` is an `input`.

6.55.3. INPUT.mixin

``mixin`` returns a mixin trait which provides an implementation of Input.read_all. `read_all` will be implemented using `read` method.

Example

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

:Trait <- [
  ... INPUT.mixin

  'read' {[:In](:Args.rest)
    stderr.print_line('Called: read')
    In.Wrapped.read(... Args)
  }

  'close' {[:In](:Args.rest)
    stderr.print_line('Called: close')
    In.Wrapped.close(... Args)
  }
]

:new_logging_input <- {(:Wrapped)
  new_val(
    ... Trait
    'Wrapped' Wrapped
  )
}

:main <- {
  :Bin = CONTROL.with_finally{(:finally)
    :In = new_logging_input(FILE.open_to_read('/etc/passwd'))
    finally{ In.close }
    In.read_all
  }
  stdout.write(Bin)
}
# Output:
#   Called: read
#   Called: read
#   Called: close
#   root:x:0:0:root:/root:/bin/bash
#   daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
#   bin:x:2:2:bin:/bin:/usr/sbin/nologin
#   sys:x:3:3:sys:/dev:/usr/sbin/nologin
#   ,,,