Skip to content

Commit 1fcc0a4

Browse files
committed
Add None-value support to Anycast
Signed-off-by: Sahas Subramanian <[email protected]>
1 parent d5e5f0a commit 1fcc0a4

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

src/frequenz/channels/_anycast.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from asyncio import Condition
99
from collections import deque
10-
from typing import Deque, Generic, Optional
10+
from typing import Deque, Generic, Type
1111

1212
from ._base_classes import Receiver as BaseReceiver
1313
from ._base_classes import Sender as BaseSender
@@ -151,6 +151,10 @@ async def send(self, msg: T) -> None:
151151
self._chan.recv_cv.notify(1)
152152

153153

154+
class _Empty:
155+
"""A sentinel value to indicate that a value has not been set."""
156+
157+
154158
class Receiver(BaseReceiver[T]):
155159
"""A receiver to receive messages from an Anycast channel.
156160
@@ -165,7 +169,7 @@ def __init__(self, chan: Anycast[T]) -> None:
165169
chan: A reference to the channel that this receiver belongs to.
166170
"""
167171
self._chan = chan
168-
self._next: Optional[T] = None
172+
self._next: T | Type[_Empty] = _Empty
169173

170174
async def ready(self) -> bool:
171175
"""Wait until the receiver is ready with a value or an error.
@@ -179,7 +183,7 @@ async def ready(self) -> bool:
179183
Whether the receiver is still active.
180184
"""
181185
# if a message is already ready, then return immediately.
182-
if self._next is not None:
186+
if self._next is not _Empty:
183187
return True
184188

185189
while len(self._chan.deque) == 0:
@@ -202,12 +206,15 @@ def consume(self) -> T:
202206
ReceiverStoppedError: if the receiver stopped producing messages.
203207
ReceiverError: if there is some problem with the receiver.
204208
"""
205-
if self._next is None and self._chan.closed:
209+
if self._next is _Empty and self._chan.closed:
206210
raise ReceiverStoppedError(self) from ChannelClosedError(self._chan)
207211

208212
assert (
209-
self._next is not None
213+
self._next is not _Empty
210214
), "`consume()` must be preceeded by a call to `ready()`"
211-
next_val = self._next
212-
self._next = None
215+
# mypy doesn't understand that the assert above ensures that self._next is not
216+
# _Sentinel. So we have to use a type ignore here.
217+
next_val: T = self._next # type: ignore[assignment]
218+
self._next = _Empty
219+
213220
return next_val

0 commit comments

Comments
 (0)