1#  You may distribute under the terms of either the GNU General Public License
2#  or the Artistic License (the same terms as Perl itself)
3#
4#  (C) Paul Evans, 2009-2012 -- leonerd@leonerd.org.uk
5
6package IO::Async::Timer;
7
8use strict;
9use warnings;
10use base qw( IO::Async::Notifier );
11
12our $VERSION = '0.800';
13
14use Carp;
15
16=head1 NAME
17
18C<IO::Async::Timer> - base class for Notifiers that use timed delays
19
20=head1 DESCRIPTION
21
22This module provides a subclass of L<IO::Async::Notifier> for implementing
23notifiers that use timed delays. For specific implementations, see one of the
24subclasses:
25
26=over 8
27
28=item *
29
30L<IO::Async::Timer::Absolute> - event callback at a fixed future time
31
32=item *
33
34L<IO::Async::Timer::Countdown> - event callback after a fixed delay
35
36=item *
37
38L<IO::Async::Timer::Periodic> - event callback at regular intervals
39
40=back
41
42=cut
43
44=head1 CONSTRUCTOR
45
46=cut
47
48=head2 new
49
50   $timer = IO::Async::Timer->new( %args )
51
52Constructs a particular subclass of C<IO::Async::Timer> object, and returns
53it. This constructor is provided for backward compatibility to older code
54which doesn't use the subclasses. New code should directly construct a
55subclass instead.
56
57=over 8
58
59=item mode => STRING
60
61The type of timer to create. Currently the only allowed mode is C<countdown>
62but more types may be added in the future.
63
64=back
65
66Once constructed, the C<Timer> will need to be added to the C<Loop> before it
67will work. It will also need to be started by the C<start> method.
68
69=cut
70
71sub new
72{
73   my $class = shift;
74   my %args = @_;
75
76   if( my $mode = delete $args{mode} ) {
77      # Might define some other modes later
78      $mode eq "countdown" or croak "Expected 'mode' to be 'countdown'";
79
80      require IO::Async::Timer::Countdown;
81      return IO::Async::Timer::Countdown->new( %args );
82   }
83
84   return $class->SUPER::new( %args );
85}
86
87sub _add_to_loop
88{
89   my $self = shift;
90   $self->start if delete $self->{pending};
91}
92
93sub _remove_from_loop
94{
95   my $self = shift;
96   $self->stop;
97}
98
99=head1 METHODS
100
101=cut
102
103=head2 is_running
104
105   $running = $timer->is_running
106
107Returns true if the Timer has been started, and has not yet expired, or been
108stopped.
109
110=cut
111
112sub is_running
113{
114   my $self = shift;
115
116   defined $self->{id};
117}
118
119=head2 start
120
121   $timer->start
122
123Starts the Timer. Throws an error if it was already running.
124
125If the Timer is not yet in a Loop, the actual start will be deferred until it
126is added. Once added, it will be running, and will expire at the given
127duration after the time it was added.
128
129As a convenience, C<$timer> is returned. This may be useful for starting
130timers at construction time:
131
132   $loop->add( IO::Async::Timer->new( ... )->start );
133
134=cut
135
136sub start
137{
138   my $self = shift;
139
140   my $loop = $self->loop;
141   if( !defined $loop ) {
142      $self->{pending} = 1;
143      return $self;
144   }
145
146   defined $self->{id} and croak "Cannot start a Timer that is already running";
147
148   if( !$self->{cb} ) {
149      $self->{cb} = $self->_make_cb;
150   }
151
152   $self->{id} = $loop->watch_time(
153      $self->_make_enqueueargs,
154      code => $self->{cb},
155   );
156
157   return $self;
158}
159
160=head2 stop
161
162   $timer->stop
163
164Stops the Timer if it is running. If it has not yet been added to the C<Loop>
165but there is a start pending, this will cancel it.
166
167=cut
168
169sub stop
170{
171   my $self = shift;
172
173   if( $self->{pending} ) {
174      delete $self->{pending};
175      return;
176   }
177
178   return if !$self->is_running;
179
180   my $loop = $self->loop or croak "Cannot stop a Timer that is not in a Loop";
181
182   defined $self->{id} or return; # nothing to do but no error
183
184   $loop->unwatch_time( $self->{id} );
185
186   undef $self->{id};
187}
188
189=head1 AUTHOR
190
191Paul Evans <leonerd@leonerd.org.uk>
192
193=cut
194
1950x55AA;
196