"Thomas SÝÓdergaard" <tsondergaard / speakanet.com> wrote in message
news:DFC899CCE177624AB6A2F121DD0CC976B55B / granada.speakanet.com...

>> Has this discussion stalled?  Matz asked for a concrete proposal about
>> a "Stream" API but none materialized.  I understand his request -- I
>> am a bit fuzzy on what this RCR is actually requesting myself.
>
>Yep, it has stalled. I posted the RCR because with rubyzip I'm faced with
the challenge of
>creating an object that can be used in place of an instance of IO. Take any
client-code that
>uses an IO instance. I'd like to be able to supply that client-code with an
instance of, say,
>ZipInputStream, and it should just work. This is trivial with java.io
streams and possible
>with C++ iostreams. It is *hard* with IO.
>
>I feel that IO mixes a lot of stuff together, which is possibly nice for
client-code, but terrible
>for implementers of IO "subclasses". Conesequently the RCR for breaking it
into
>orthogonal parts, that can easily be specialized and reused. Implementing a
new datasink
>should be a matter of implementing a very simple interface, e.g with two
methods write
>(aString) and close. It should not be necessary to reimplement convenience
methods such
>as puts, printf, etc. The same goes for data sources.

As far as ZIP files, or MIME-encoded email, that doesn't seem to me a stream
issue, but more of a "resource managment" issue.  Perhaps an object
abstraction which allows derivations to enumerate their resources, complete
with MIME type information, etc., could be of use there.  They could, in
turn, use streams to send/receive their resources, however.

But where I/O is concerned, here's a base implementation that I use and have
found very extensible to all sorts of streams.  Currently, I have stdio,
file, sockets (plain and SSL), string and memory buffers using a system of
class functionally identical to what I describe below:

result code ranges:

    success
    endoffile
    tryagain
    closed
    readerror
    writeerror
    buffererror
    timeout

pure base abstraction (which must be implemented by any derivations)

    bool _rewind

    long _getlength

    long _tell
    long _seek

    result _truncate

    result _read(buffer, size)
    result _write(buffer, size)

    result _waitforread(seconds)
    result _waitforwrite(seconds)

base implementation, inherits pure base

    bool rewind

    long getlength

    long tell
    long seek

    result truncate

    result putc
    result getc
    result peekc

    result puts
    result gets

    result printf

    result read
    result write

The pure base abstraction contains functions which all must be implemented
by the higher derivations.  Even if they just give an error because they
don't support the feature.  For the most part, it just reads and writes
blocks of data which are then maintained in a buffer by the base
implementation.

The base implementation does most of the grunt work, reading and maintaining
an internal data buffer for efficiency (speed mostly), reallocating the
buffer when it has run out, etc.  When calls are made to seek, truncate or
rewind on streams that support it the buffer is destroyed and the true I/O
pointer is corrected to reflect where it should be were the data not being
buffered.

Essentially, any IO stream that can read and write should be able to use
this sort of abstraction.  When it can't support seeking, etc, oh well, toss
an error.

    Sean