10
10
11
11
namespace HH\Lib\Async ;
12
12
13
+ use namespace HH\Lib\_Private ;
14
+
13
15
/**
14
16
* A wrapper around ConditionWaitHandle that allows notification events
15
17
* to occur before the condition is awaited.
16
18
*/
17
- class Condition <T > {
18
- private ?Awaitable < T > $condition = null ;
19
+ class Condition <T > implements ConditionNotifyee <T > {
20
+ private _Private \ConditionState < T > $state ;
21
+ public function __construct () {
22
+ $this -> state = _Private \NotStarted :: getInstance();
23
+ }
24
+
25
+ public function setState (_Private \ConditionState <T > $state ): void {
26
+ $this -> state = $state ;
27
+ }
19
28
20
- /**
21
- * Notify the condition variable of success and set the result.
22
- */
23
29
final public function succeed (T $result ): void {
24
- invariant ($this -> trySucceed($result ), ' Unable to notify Condition twice' );
30
+ invariant (
31
+ $this -> state -> trySucceed($this , $result ),
32
+ ' Unable to notify Condition twice' ,
33
+ );
25
34
}
26
35
27
- /**
28
- * Notify the condition variable of failure and set the exception.
29
- */
30
36
final public function fail (\Exception $exception ): void {
31
- invariant ($this -> tryFail($exception ), ' Unable to notify Condition twice' );
37
+ invariant (
38
+ $this -> state -> tryFail($this , $exception ),
39
+ ' Unable to notify Condition twice' ,
40
+ );
32
41
}
33
42
34
- /**
35
- * Notify the condition variable of success and set the $result.
36
- *
37
- * @return
38
- * true if the condition is set to $result successfully, false if the
39
- * condition was previously set to another result or exception.
40
- */
41
43
final public function trySucceed (T $result ): bool {
42
- if ($this -> condition === null ) {
43
- $this -> condition = async {
44
- return $result ;
45
- };
46
- return true ;
47
- } else {
48
- if (! ($this -> condition is ConditionWaitHandle < _ > )) {
49
- return false ;
50
- }
51
- /* HH_FIXME[4110]: Type error revealed by type-safe instanceof feature. See https://fburl.com/instanceof */
52
- $this -> condition -> succeed($result );
53
- return true ;
54
- }
44
+ return $this -> state -> trySucceed($this , $result );
55
45
}
56
46
57
- /**
58
- * Notify the condition variable of failure and set the $exception.
59
- *
60
- * @return
61
- * true if the condition is set to $exception successfully, false if the
62
- * condition was previously set to another result or exception.
63
- */
64
47
final public function tryFail (\Exception $exception ): bool {
65
- if ($this -> condition === null ) {
66
- $this -> condition = async {
67
- throw $exception ;
68
- };
69
- return true ;
70
- } else {
71
- if (! ($this -> condition is ConditionWaitHandle < _ > )) {
72
- return false ;
73
- }
74
- $this -> condition -> fail($exception );
75
- return true ;
76
- }
48
+ return $this -> state -> tryFail($this , $exception );
77
49
}
78
50
79
51
/**
@@ -90,9 +62,54 @@ final public function tryFail(\Exception $exception): bool {
90
62
final public async function waitForNotificationAsync (
91
63
Awaitable <void > $notifiers ,
92
64
): Awaitable <T > {
93
- if ($this -> condition === null ) {
94
- $this -> condition = ConditionWaitHandle :: create($notifiers );
95
- }
96
- return await $this -> condition ;
65
+ return await $this -> state -> waitForNotificationAsync($this , $notifiers );
97
66
}
98
67
}
68
+
69
+
70
+ /**
71
+ * Asynchronously wait for the condition variable to be notified and
72
+ * return the result or throw the exception received via notification.
73
+ *
74
+ * The caller must provide an Awaitable $notifiers (which must be a
75
+ * WaitHandle) that must not finish before the notification is received.
76
+ * This means $notifiers must represent work that is guaranteed to
77
+ * eventually trigger the notification. As long as the notification is
78
+ * issued only once, asynchronous execution unrelated to $notifiers is
79
+ * allowed to trigger the notification.
80
+ */
81
+ function wait_for_notification_async <T >(
82
+ (function (ConditionNotifyee <T >): Awaitable <void >) $notifiers ,
83
+ ): Awaitable <T > {
84
+ $condition = new Condition ();
85
+ return $condition -> waitForNotificationAsync($notifiers ($condition ));
86
+ }
87
+
88
+ interface ConditionNotifyee <-T > {
89
+
90
+ /**
91
+ * Notify the condition variable of success and set the $result.
92
+ */
93
+ public function succeed (T $result ): void ;
94
+ /**
95
+ * Notify the condition variable of success and set the $result.
96
+ *
97
+ * @return
98
+ * true if the condition is set to $result successfully, false if the
99
+ * condition was previously set to another result or exception.
100
+ */
101
+ public function trySucceed (T $result ): bool ;
102
+
103
+ /**
104
+ * Notify the condition variable of failure and set the exception.
105
+ */
106
+ public function fail (\Exception $exception ): void ;
107
+ /**
108
+ * Notify the condition variable of failure and set the $exception.
109
+ *
110
+ * @return
111
+ * true if the condition is set to $exception successfully, false if the
112
+ * condition was previously set to another result or exception.
113
+ */
114
+ public function tryFail (\Exception $exception ): bool ;
115
+ }
0 commit comments