device-streams
**************

This file describes a proposed extensible streams standard.

Copyright © 2004 Rudi Schlatte, Bruno Haible

Issue
=====

CL Gray streams are a high level stream customization ability.  We need a low-level customization ability as well.

Proposal
========

     ;;;; rudi (2004-10-09): common-lisp:stream can not be subclassed;
     ;;;; what is device-stream a subclass of?

Add a class 'device-stream' which is a subclass of stream of metaclass standard-class.  An instance of a subclass of device-stream is meant to manage an "underlying device", e.g. a file or socket.

API
===

The device-stream interface consists of the following generic functions.  No predefined methods exist on these generic functions.

     ;;;; rudi (2004-07-09): we should also specify the conditions that are
     ;;;; thrown, if any.  My gut feeling would be to work with return
     ;;;; values only and throw conditions farther up, what do you think?

Additionally, device-streams are unbuffered streams (in the Common Lisp sense) of type (unsigned-byte 8), so can be used as arguments for read-byte etc.

 -- Function: device-open device &rest initargs => result

     DEVICE: an instance of device-stream

     INITARGS: options specific to the actual type of DEVICE

     RESULT: a generalized boolean

     device-open performs the device-specific operations to open the underlying device, taking any needed information from INITARGS. RESULT is true if the device could be successfully opened, false if not.

 -- Function: device-close device

     DEVICE: an instance of device-stream

     device-close closes the underlying device.

 -- Function: device-read device buffer start end blocking => result

     DEVICE: an instance of device-stream

     BUFFER: an object of type (simple-array (unsigned-byte 8) (*))

     START, END: fixnums, with START <= END.

     BLOCKING: a generalized boolean

     RESULT: a fixnum

     device-read attempts to fill BUFFER starting at position START up to position END (exclusive) with bytes read from the device.  device-read returns the number of bytes read or the symbol :eof if it encountered an end-of-file before reading the first byte.  If BLOCKING is true, the return value will not be zero and device-read blocks until at least one byte was read.  If BLOCKING is false, device-read returns without waiting; in that case, it returns 0 if no input is immediately available.

 -- Function: device-write device buffer start end blocking => result

     DEVICE: an instance of device-stream

     BUFFER: an object of type (simple-array (unsigned-byte 8) (*))

     START, END: fixnums, with START <= END.

     BLOCKING: a generalized boolean

     RESULT: a fixnum

     device-write attempts to write the contents of BUFFER starting at position START up to position END (exclusive) to the device.  device-write returns the buffer index of the first octet that was not written to the device or :eof if it encountered an end-of-file before writing the first byte or the value of END if all of the buffer contents between START and END was written to the device.  If BLOCKING is true, the return value will be greater than START and device-write blocks until at least one byte was written.  If BLOCKING is false, device-write returns without waiting; it returns the value of START if no output could be written to the device in that case.

 -- Function: device-clear-input device

     DEVICE: an instance of device-stream

     device-clear-input performs any device-specific operations necessary to discard any input pending on the underlying device, including clearing any os-level buffers or similar.

 -- Function: device-clear-output device

     DEVICE: an instance of device-stream

     device-clear-output performs any device-specific operations necessary to discard any output pending on the underlying device, including clearing any os-level buffers or similar.

 -- Function: device-flush-output device blocking

          ;;;; rudi (2004-10-09): device-flush-output instead of
          ;;;; device-finish-output, device-force-output since the blocking
          ;;;; parameter exists everywhere else as well (it seems more in line
          ;;;; with the other methods, but I don't insist on this change)

     DEVICE: an instance of device-stream

     BLOCKING: a generalized boolean

     device-flush-output performs any device-specific operations necessary to flush any output pending on the underlying device.  If BLOCKING is true, device-flush-output will make a best effort to block until the underlying device confirms completion of the output. If BLOCKING is false, device-finish-output returns immediately.

 -- Function: device-file-position device => result

     DEVICE: an instance of device-stream

     RESULT: an integer or nil

     device-file-position returns the file position of the underlying device (e.g. an unsigned-byte offset from the beginning of a file) as an integer.  If such a file position cannot be meaningfully given, device-file-position returns nil.

 -- Function: (setf device-file-position) device new-position => result

     DEVICE: an instance of device-stream

     NEW-POSITION: an integer

     RESULT: a generalized boolean

     (setf device-file-position) sets the file position of the underlying device, if applicable.  RESULT is true if the operation succeeded, false if the operation failed or if the file position cannot be meaningfully set for the underlying device.

 -- Function: device-file-length device => result

     DEVICE: an instance of device-stream

     RESULT: an integer or nil

     device-file-length returns the file length of the underlying file (if applicable) or nil.