File Coverage

lib/Context/Singleton/Frame/Promise.pm
Criterion Covered Total %
statement 67 70 95.7
branch 10 14 71.4
condition 5 6 83.3
subroutine 22 23 95.6
pod 0 14 0.0
total 104 127 81.8


line stmt bran cond sub pod time code
1              
2 4     4   109390 use strict;
  4         16  
  4         117  
3 4     4   22 use warnings;
  4         6  
  4         200  
4              
5             package Context::Singleton::Frame::Promise;
6              
7             our $VERSION = v1.0.4;
8              
9 4     4   21 use Scalar::Util qw[ weaken ];
  4         8  
  4         246  
10              
11 4     4   2132 use namespace::clean;
  4         37593  
  4         25  
12              
13             sub new {
14 150     150 0 27174 my ($class, %params) = @_;
15              
16             bless {
17             depth => $params{depth},
18 150         969 is_resolvable => 0,
19             dependencies => [],
20             listeners => {},
21             }, $class;
22             }
23              
24             sub depth {
25 4     4 0 16 $_[0]->{depth};
26             }
27              
28             sub value {
29 59     59 0 4482 $_[0]->{value};
30             }
31              
32             sub set_value {
33 80     80 0 39730 my ($self, $value, $in_depth) = @_;
34              
35 80   66     201 $in_depth //= $self->depth;
36              
37 80 100       151 unless ($self->is_deduced) {
38 65         229 $self->{value} = $value;
39 65         152 $self->set_deducible ($in_depth);
40             }
41              
42 80         171 $self;
43             }
44              
45             sub is_deduced {
46 205     205 0 73740 exists $_[0]->{value};
47             }
48              
49             sub is_deducible {
50 670     670 0 23569 $_[0]->{is_deducible};
51             }
52              
53             sub set_deducible {
54 172     172 0 339 my ($self, $in_depth) = @_;
55              
56 172 100 100     325 unless ($self->is_deducible and $self->deduced_in_depth >= $in_depth) {
57 129         234 $self->{is_deducible} = 1;
58 129         324 $self->_set_deduced_in_depth ($in_depth);
59 129         273 $self->_broadcast_deducible;
60             }
61              
62 172         354 $self;
63             }
64              
65             sub deduced_in_depth {
66 297     297 0 13616 $_[0]->{in_depth};
67             }
68              
69             sub _set_deduced_in_depth {
70 129     129   285 $_[0]->{in_depth} = $_[1];
71             }
72              
73             sub _listeners {
74 247     247   420 $_[0]->{listeners};
75             }
76              
77             sub add_listeners {
78 118     118 0 252 my ($self, @new_listeners) = @_;
79              
80             # - Listener life time is a frame it is created for
81             # weaken helps tracking them (children do listen parents here)
82             # - Listener is another promise
83             # - Listeners are stored in linked list
84              
85 118         210 my $head = $self->_listeners;
86 118         249 for my $listener (@new_listeners) {
87             my $entry = $head->{next} = {
88             prev => $head,
89             next => $head->{next},
90 118         437 listener => $listener,
91             };
92              
93             $entry->{next}{prev} = $head->{next}
94 118 100       611 if $entry->{next};
95              
96 118         414 Scalar::Util::weaken $entry->{listener};
97              
98             $self->_notify_listener ($entry->{listener})
99 118 100       228 if $self->is_deducible;
100             }
101              
102 118         242 $self;
103             }
104              
105             sub listen {
106 8     8 0 25 my ($self, @promises) = @_;
107              
108 8         22 for my $promise (grep defined, @promises) {
109 9         22 $promise->add_listeners ($self);
110             }
111              
112 8         20 $self;
113             }
114              
115             sub _dependencies {
116 257     257   759 $_[0]->{dependencies};
117             }
118              
119             sub add_dependencies {
120 118     118 0 266 my ($self, @new_dependencies) = @_;
121              
122 118         300 @new_dependencies = grep defined, @new_dependencies;
123              
124 118         241 for my $dependency (@new_dependencies) {
125 109         152 push @{ $self->_dependencies }, $dependency;
  109         263  
126             #Scalar::Util::weaken ($self->_dependencies->[-1]);
127             }
128              
129 118         282 $_->add_listeners ($self) for @new_dependencies;
130              
131 118         252 $self;
132             }
133              
134             sub dependencies {
135 148     148 0 218 @{ $_[0]->_dependencies };
  148         270  
136             }
137              
138             sub deducible_dependencies {
139 118     118 0 204 my ($self) = @_;
140              
141 118         250 grep { $_->is_deducible } $self->dependencies;
  156         303  
142             }
143              
144             sub _broadcast_deducible {
145 129     129   208 my ($self) = @_;
146              
147 129 50       222 return unless $self->is_deducible;
148              
149 129         266 my $head = $self->_listeners;
150 129         312 while ($head = $head->{next}) {
151 8 50       21 unless ($head->{listener}) {
152             # obsoleted weak listener
153 0         0 $head->{prev}{next} = $head->{next};
154             $head->{next}{prev} = $head->{prev}
155 0 0       0 if $head->{next};
156 0         0 next;
157             }
158              
159 8         29 $self->_notify_listener ($head->{listener});
160             }
161              
162 129         215 $self;
163             }
164              
165       0 0   sub notify_deducible {
166             }
167              
168             sub _notify_listener {
169 89     89   190 my ($self, $listener) = @_;
170              
171 89         199 $listener->notify_deducible ($self->deduced_in_depth);
172             }
173              
174             1;
175              
176             __END__