port-channel
1 Model
2 Reference
make-port-channel
port-channel?
port-channel-direction
port-channel-put
port-channel-get
port-channel-try-get
port-channel-evt
close-port-channel
port-channel-wait
3 Errors
port-channel-error
port-channel-error-get
port-channel-error-try-get
port-channel-error-evt
4 Example
5 Serializable structures
9.2

port-channel🔗ℹ

Hans Dijkema <hans@dijkewijk.nl>

 (require port-channel) package: port-channel

The port-channel module wraps a Racket port as an asynchronous, channel-like object. It is intended as a small building block for stream-based communication protocols, for example between a parent Racket process and a subprocess connected through standard input and standard output.

A port-channel transports serialized Racket values. The implementation uses racket/serialize: values are passed through serialize, written to the port, read back as Racket data and reconstructed with deserialize. Ordinary data values work directly. Custom structures must be defined with serializable-struct. Ports, threads, custodians and ordinary procedures are not serializable values.

1 Model🔗ℹ

A port-channel has one of two directions:

  • 'input: a reader thread reads complete serialized values from an input port and puts the deserialized values on an internal asynchronous channel. The port-channel is itself a synchronizable event, so (sync pc) returns the next complete value.

  • 'output: port-channel-put queues values on an internal asynchronous channel. A writer thread serializes and writes queued values to the output port.

Buffered I/O alone is not enough to provide this behaviour. Synchronizing on a raw input port only says that some input is available; it does not guarantee that a complete serialized value is ready. The reader thread converts the byte stream into complete channel messages.

2 Reference🔗ℹ

procedure

(make-port-channel port    
  [#:direction direction    
  #:source source    
  #:close? close?])  port-channel?
  port : port?
  direction : (or/c 'auto 'input 'output) = 'auto
  source : any/c = 'port
  close? : any/c = #t
Creates a port-channel for port. With 'auto, the direction is inferred from the port. An input-only port becomes an input port-channel. An output-only port becomes an output port-channel. If the port is both an input and an output port, #:direction must be supplied explicitly.

The source value is stored in reported port-channel-error values. When close? is true, close-port-channel closes the underlying port.

procedure

(port-channel? v)  boolean?

  v : any/c
Returns true when v is a port-channel.

procedure

(port-channel-direction pc)  (or/c 'input 'output)

  pc : port-channel?
Returns the direction of pc.

procedure

(port-channel-put pc v)  void?

  pc : port-channel?
  v : any/c
Queues v for writing to an output port-channel. The call only enqueues the value; serialization and port I/O are performed by the writer thread.

The value must be serializable by serialize. If serialization or writing fails, a port-channel-error is published on the error channel.

procedure

(port-channel-get pc)  any/c

  pc : port-channel?
Returns the next value from an input port-channel. This is equivalent to (sync pc). When the underlying input stream reaches end-of-file, eof is published as the final value.

procedure

(port-channel-try-get pc)  any/c

  pc : port-channel?
Attempts to get a value from an input port-channel without blocking. Returns #f when no value is currently available.

procedure

(port-channel-evt pc)  evt?

  pc : port-channel?
Returns pc as a synchronizable event. This is mainly a convenience for code that wants an explicit event-producing function.

procedure

(close-port-channel pc)  void?

  pc : port-channel?
Closes the port-channel. For an input port-channel, this closes the input port. For an output port-channel, a close marker is queued, so values already queued before the close marker are written first.

procedure

(port-channel-wait pc)  void?

  pc : port-channel?
Waits until the reader or writer thread of pc has terminated.

3 Errors🔗ℹ

struct

(struct port-channel-error (source message))

  source : any/c
  message : string?
Represents an error reported by the reader or writer thread.

Blocks until the next error is available.

procedure

(port-channel-error-try-get pc)  any/c

  pc : port-channel?
Attempts to get the next error without blocking. Returns #f when no error is currently available.

procedure

(port-channel-error-evt pc)  evt?

  pc : port-channel?
Returns the error channel as a synchronizable event.

4 Example🔗ℹ

(require port-channel)
 
(define-values (in out) (make-pipe))
 
(define reader (make-port-channel in))
(define writer (make-port-channel out))
 
(port-channel-put writer '(hello 1 2 3))
(sync reader)

The result is:

'(hello 1 2 3)

5 Serializable structures🔗ℹ

(require racket/serialize
         port-channel)
 
(serializable-struct message (id payload) #:transparent)
 
(define-values (in out) (make-pipe))
(define reader (make-port-channel in))
(define writer (make-port-channel out))
 
(port-channel-put writer (message 1 '(a b c)))
(sync reader)

The received value is a reconstructed message structure.