#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#  (C) Paul Evans, 2019 -- leonerd@leonerd.org.uk

package Future::Queue;

use v5.10;
use strict;
use warnings;

our $VERSION = '0.48';

=head1 NAME

C<Future::Queue> - a FIFO queue of values that uses L<Future>s


   use Future::Queue;

   my $queue = Future::Queue->new;

   my $f = repeat {
      $queue->shift->then(sub {
         my ( $thing ) = @_;

   $queue->push( "a thing" );


Objects in this class provide a simple FIFO queue the stores arbitrary perl
values. Values may be added into the queue using the L</push> method, and
retrieved from it using the L</shift> method.

Values may be stored within the queue object for C<shift> to retrieve later,
or if the queue is empty then the future that C<shift> returns will be
completed once an item becomes available.




=head2 new

   $queue = Future::Queue->new

Returns a new C<Future::Queue> instance.


sub new
   my $class = shift;
   return bless {
      items => [],
      waiters => [],
   }, $class;

=head2 push

   $queue->push( $item )

Adds a new item into the queue. If the queue was previously empty and there is
at least one C<shift> future waiting, then the next one will be completed by
this method.


sub push :method
   my $self = shift;
   my ( $item ) = @_;

   push @{ $self->{items} }, $item;
   ( shift @{ $self->{waiters} } )->done if @{ $self->{waiters} };

=head2 shift

   $item = $queue->shift->get

Returns a C<Future> that will yield the next item from the queue. If there is
already an item then this will be taken and the returned future will be
immediate. If not, then the returned future will be pending, and the next
C<push> method will complete it.


sub shift :method
   my $self = shift;

   if( @{ $self->{items} } ) {
      return Future->done( shift @{ $self->{items} } );

   push @{ $self->{waiters} }, my $f = Future->new;
   return $f->then(sub {
      return Future->done( shift @{ $self->{items} } );

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>