NAME

    Future::Selector - manage a collection of pending futures

SYNOPSIS

       use Future::AsyncAwait;
       use Future::IO;
       use Future::Selector;
       use IO::Socket::IP;
    
       my $selector = Future::Selector->new;
    
       my $listensock = IO::Socket::IP->new(
          LocalHost => "::1",
          LocalPort => "8191",
          Listen => 1,
       );
    
       $selector->add(
          data => "listener",
          gen  => sub { Future::IO->accept( $listensock ) },
       );
    
       while(1) {
          my @ready = await $selector->select;
    
          ...
       }

DESCRIPTION

    Objects in this class maintain a collection of pending Future
    instances, and manage the lifecycle of waiting for their eventual
    completion. This provides a central structure for writing asynchronous
    event-driven programs using Future and Future::IO-based logic.

    When writing an asynchronous Future-based client, often the program can
    be structured similar to a straight-line synchronous program, where at
    any point the client is just waiting on sending or receiving one
    particular message or data-flow. It therefore suffices to use a simple
    call/response structure, perhaps written using the async and await
    keywords provided by Future::AsyncAwait.

    In contrast, a server program often has many things happening at once.
    It will be handling multiple clients simultaneously, as well as waiting
    for new client connections and any other internal logic it requires to
    provide data to those clients. There is not just one obvious pending
    future at any one time; there could be several that all need to be
    monitored for success or failure.

    A Future::Selector instance helps this situation, by storing an entire
    set of pending futures that represent individual sub-divisions of the
    work of the program (or a part of it). As each completes, the selector
    instance informs the containing code so it can continue to perform the
    work required to handle that part, perhaps resulting in more future
    instances for the selector to manage.

 Program Structure

    As per the SYNOPSIS example, a typical server-style program would
    probably be structured around a while(1){} loop that repeatedly awaits
    on the next select future from the selector instance, looking for the
    next thing to do. The data values stored with each future and returned
    by the select method can be used to help direct the program into
    working out what is going on. For example, string names or object
    instances could help identify different kinds of next step.

       use v5.36;
    
       ...
    
       $selector->add(
          data => "listener",
          gen  => sub { Future::IO->accept( $listensock ) },
       );
    
       while(1) {
          foreach my ( $data, $f ) ( await $selector->select ) {
             if( $data eq "listener" ) {
                # a new client has been accept()ed. should now set up handling
                # for it in some manner.
    
                my $sock = await $f;
                my $clientconn = ClientConnection->new( fh => $sock );
    
                $selector->add( data => $clientconn, f => $clientconn->run );
             }
             elsif( $data isa ClientConnection ) {
                # an existing connection's runloop has terminated. should now
                # handle that in whatever way is appropriate
                ...
             }
             ...
          }
       }

    Alternatively, if each stored future instance already performed all of
    the work required to handle it before it yields success, there may be
    nothing for the toplevel application loop to do other than repeatedly
    wait for things to happen.

       $selector->add(
          data => undef, # ignored
          gen  => async sub {
             my $sock = await Future::IO->accept( $listensock );
             my $clientconn = ClientConnection->new( fh => $sock );
    
             $selector->add( data => undef, f => $clientconn->run );
          }
       );
    
       await $selector->select while 1;

    Failure propagation by the select method here ensures any errors
    encountered by individual component futures are still passed upwards
    through the program structure, ultimately ending at the toplevel if
    nothing else catches it first.

 Comparison With select(2), epoll, etc..

    In some ways, the operation of this class is similar to system calls
    like select(2) and poll(2). However, there are several key differences:

      * Future::Selector stores high-level futures, rather than operating
      directly on system-level filehandles. As such, it can wait for
      application-level events and workflow when those things are
      represented by futures.

      * The main waiting call, "select", is a method that returns a future.
      This could be returned from some module or component of a program, to
      be awaited on by another outer Future::Selector instance. The
      application is not limited to exactly one as would be the case for
      blocking system calls, but can instead create a hierarchical
      structure out of as many instances as are required.

      * Once added, a given future remains a member of a Future::Selector
      instance until it eventually completes; which may require many calls
      to the select method (or indeed, it may never complete during the
      lifetime of the program, for tasks that should keep pending
      throughout). In this way, the object is more comparable to persistent
      system-level schedulers like Linux's epoll or BSD's kqueue
      mechanisms, than the one-shot nature of select(2) or poll(2)
      themselves.

METHODS

 add

       $selector->add( data => $data, f => $f );

    Adds a new future to the collection.

    After the future becomes ready, the currently-pending select future (or
    the next one to be created) will complete. It will yield the given data
    and future instance if this future succeeded, or fail with the same
    failure if this future failed. At that point it will be removed from
    the stored collection. If the item future was cancelled, it is removed
    from the collection but otherwise ignored; the select future will
    continue waiting for another result.

       $selector->add( data => $data, gen => $gen );
    
          $f = $gen->();

    Adds a new generator of futures to the collection.

    The generator is a code reference which is used to generate a future,
    which is then added to the collection similar to the above case. Each
    time the future becomes ready, the generator is called again to create
    another future to continue watching. This continues until the generator
    returns undef.

 select

       ( $data1, $f1, $data2, $f2, ... ) = await $selector->select();

    Returns a future that will become ready when at least one of the stored
    futures is ready. It will yield an even-sized list of pairs, giving the
    associated data and original (now-completed) futures that were stored.

    If you are intending to run the loop indefinitely, be careful not to
    write code such as

       1 while await $selector->select;

    because in scalar context, the awaited future will yield its first
    value, which will be the data associated with the first completed
    future. If that data value was false (such as undef) then the loop will
    stop running at that point. Generally in these sorts of situations you
    want to use "run" or "run_until_ready".

 run

       await $selector->run();

    Since version 0.02.

    Returns a future that represents repeatedly calling the "select" method
    indefinitely. This will not return, except that if any of the contained
    futures fails then this will fail the same way.

    This is most typically used at the toplevel of a server-type program,
    one where there is no normal exit condition and the program is expected
    to remain running unless some fatal error happens.

 run_until_ready

       @result = await $selector->run_until_ready( $f );

    Since version 0.02.

    Returns a future that represents repeatedly calling the "select" method
    until the given future instance is ready. When it becomes ready (either
    by success or failure) the returned future will yield the same result.
    If the returned future is cancelled, then $f itself will be cancelled
    too. This will not cancel a concurrently-pending select or run call,
    however.

    The given future will be added to the selector by calling this method;
    you should not call "add" on it yourself first.

    This is typically used in client or hybrid code, or as a nested
    component of a server program, which needs to wait on a result while
    also performing other background tasks.

    Remember that since this method itself returns a future, it could
    easily serve as the input to another outer-level selector instance.

TODO

      * Convenience ->add_f / ->add_gen

      * Configurable behaviour on component future failure

AUTHOR

    Paul Evans <leonerd@leonerd.org.uk>

