NAME

    Future::Buffer - a string buffer that uses Futures

SYNOPSIS

       use Future::Buffer;
    
       use Future::AsyncAwait;
       use Future::IO;
    
       my $buffer = Future::Buffer->new(
          fill => sub { Future::IO->sysread( $socket, 8192 ) }
       );
    
       async sub print_lines
       {
          while(1) {
             my $line = await $buffer->read_until( "\n" );
             chomp $line;
    
             say "Got a line: $line";
          }
       }
    
       await print_lines();

DESCRIPTION

    Objects in this class provide a string buffer, on which operations
    return Future instances which will complete when data is available.
    Data can be inserted into the buffer either in a push-based manner by
    calling the write method, or in a pull-based manner by providing it
    with a fill callback by which it can request data itself. This
    flexibility allows the buffer to act as an adapter between push- and
    pull-based providers and consumers.

    Each read-like method returns a Future which will complete once there
    are enough bytes in the buffer to satisfy the required condition. The
    buffer behaves somewhat like a pipe, where bytes provided at the
    writing end (either by the write method or the fill callback) are
    eventually consumed at the reading end by one of the read futures.

    Multiple read futures can remain pending at once, and will be completed
    in the order they were created when more data is eventually available.
    Thus, any call to the write method to provide more data can potentially
    result in multiple futures becoming ready.

    Since version 0.04 the buffer supports an end-of-file condition. The
    "close" method or a fill callback future yielding an empty result will
    mark that the buffer is now closed. Once it has exhausted the remaining
    stored data any further read futures will yield empty.

CONSTRUCTOR

 new

       $buffer = Future::Buffer->new( %args );

    Returns a new Future::Buffer instance.

    Takes the following named arguments:

    fill => CODE

         $data = await $fill->();

      Optional callback which the buffer will invoke when it needs more
      data.

      Any read futures which are waiting on the fill future are constructed
      by using the fill future as a prototype, ensuring they have the
      correct type.

      If the result is an empty list this will be treated as an end-of-file
      notification and the buffer is closed.

METHODS

 length

       $len = $buffer->length;

    Returns the length of the currently-stored data; that is, data that has
    been provided by write calls or the fill callback but not yet consumed
    by a read future.

 is_empty

       $empty = $buffer->is_empty;

    Returns true if the stored length is zero.

 write

       $f = $buffer->write( $data );

    Appends to the stored data, invoking any pending read futures that are
    outstanding and can now complete.

    Currently this method returns an already-completed Future. Some later
    version may implement a buffer maximum size, and choose not to complete
    this future until there is enough space to accept the new data. For now
    it is safe for the caller to ignore the return value, but it may become
    not so.

 close

       $buffer->close;

    Marks that the buffer is now at EOF condition. Once any remaining
    buffered content is consumed, any further read futures will all yield
    EOF condition.

 read_atmost

       $data = await $buffer->read_atmost( $len );

    Returns a future which will complete when there is some data available
    in the buffer and will yield up too the given length. Note that,
    analogous to calling the read IO method on a filehandle, this can still
    complete and yield a shorter length if less is currently available.

    If the stream is closed and there is no remaining data, the returned
    future will yield empty.

 read_exactly

       $data = await $buffer->read_exactly( $len );

    Returns a future which will complete when there is enough data
    available in the buffer to yield exactly the length given.

    If the stream is closed and there is no remaining data, the returned
    future will yield empty.

 read_until

       $data = await $buffer->read_until( $pattern );

    Returns a future which will complete when the buffer contains a match
    for the given pattern (which may either be a plain string or a compiled
    Regexp). The future will yield the contents of the buffer up to and
    including this match.

    If the stream is closed and there is no remaining data, the returned
    future will yield empty.

    For example, a readline-like operation can be performed by

       $f = $buffer->read_until( "\x0d\x0a" );

 read_unpacked

       $data = await $buffer->read_unpacked( $pack_format );

    Since version 0.03.

    Returns a future which will complete when the buffer contains enough
    data to unpack all of the requested fields using the given pack()
    format. The future will yield a list of all the fields extracted by the
    format.

    If the stream is closed and there is no remaining data, the returned
    future will yield empty.

    Note that because the implementation is shamelessly stolen from
    IO::Handle::Packable the same limitations on what pack formats are
    recognized will apply.

 unread

       $buffer->unread( $data );

    Since version 0.03.

    Prepends more data back into the buffer,

    It is uncommon to need this method, but it may be useful in certain
    situations such as when it is hard to determine upfront how much data
    needs to be read for a single operation, and it turns out too much was
    read. The trailing content past what is needed can be put back for a
    later operation.

    Note that use of this method causes an inherent race condition between
    outstanding read futures and existing data in the buffer. If there are
    no pending futures then this is safe. If there is no existing data
    already in the buffer this is also safe. If neither of these is true
    then a warning is printed indicating that the logic of the caller is
    not well-defined.

TODO

      * An "on-read" event, taking maybe inspiration from
      IO::Async::Stream. This would allow both pull- and push-based
      consumers.

      * Size limitation. Allow an upper bound of stored data, make write
      calls return pending futures until buffer can accept it. Needs
      consideration of unbounded read_until though.

      * Consider extensions of the "read_unpacked" method to handle more
      situations. This may require building a shared CPAN module for doing
      streaming-unpack along with IO::Handle::Packable and other
      situations.

AUTHOR

    Paul Evans <leonerd@leonerd.org.uk>

    Inspired by Ryu::Buffer by Tom Molesworth <TEAM@cpan.org>

