1010
1111namespace HH\Lib\Async ;
1212
13+ use namespace HH\Lib\_Private ;
14+
1315/**
1416 * A wrapper around ConditionWaitHandle that allows notification events
1517 * to occur before the condition is awaited.
1618 */
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+ }
1928
20- /**
21- * Notify the condition variable of success and set the result.
22- */
2329 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+ );
2534 }
2635
27- /**
28- * Notify the condition variable of failure and set the exception.
29- */
3036 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+ );
3241 }
3342
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- */
4143 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 );
5545 }
5646
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- */
6447 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 );
7749 }
7850
7951 /**
@@ -90,9 +62,54 @@ final public function tryFail(\Exception $exception): bool {
9062 final public async function waitForNotificationAsync (
9163 Awaitable <void > $notifiers ,
9264 ): 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 );
9766 }
9867}
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