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