1# ty: ignore[unresolved-attribute]
2from asyncutils._internal.helpers import copy_and_clear, fullname, simple_wrap
3from asyncutils._internal.submodules import futures_all as __all__
4from contextvars import copy_context
5from asyncio.futures import Future, _PyFuture # ty: ignore[unresolved-import]
6from asyncio.tasks import Task, _PyTask # ty: ignore[unresolved-import]
7from sys import audit
8from time import monotonic_ns
9t = '_callbacks', '_async_callbacks', '_noargs_callbacks', '_noargs_async_callbacks'
10def f(a, /):
11 def remove_callback(self, f, /):
12 if r := len(C := getattr(self, a))-len(l := tuple(t for t in C if t[0] is not f)): C[:] = l
13 return r
14 return remove_callback
15class A:
16 def __init__(self, *a, **k): super().__init__(*a, **k); self._async_callbacks, self._noargs_callbacks, self._noargs_async_callbacks = (c := type(self)._mcb)(), c(), c()
17 def add_async_callback(self, f, /, *, context=None):
18 if self._state == 'PENDING': type(self)._acb(self._async_callbacks, f, context)
19 else: self._loop.create_task(simple_wrap(f(self)), context=context)
20 def add_noargs_callback(self, f, /, *, context=None):
21 if self._state == 'PENDING': type(self)._acb(self._noargs_callbacks, f, context)
22 else: self._loop.call_soon(f, context=context)
23 def add_noargs_async_callback(self, f, /, *, context=None):
24 if self._state == 'PENDING': type(self)._acb(self._noargs_async_callbacks, f, context)
25 else: self._loop.create_task(simple_wrap(f()), context=context)
26 def _Future__schedule_callbacks(self): # noqa: N802
27 audit(f'{fullname(self)}/schedule_callbacks', id(self)); a, b = (l := self._loop).create_task, l.call_soon; c, d, e, f = map(type(self)._icb, (self._async_callbacks, self._callbacks, self._noargs_async_callbacks, self._noargs_callbacks))
28 for g, _ in c: a(g(self), context=_)
29 for g, _ in d: b(g, self, context=_)
30 for g, _ in e: a(g(), context=_)
31 for g, _ in f: b(g, context=_)
32class B:
33 def __init__(self, *a, **k): self._creation_time = monotonic_ns(); super().__init__(*a, **k)
34 def __lt__(self, o, /): return self._creation_time < o._creation_time
35class C(A): _acb, _icb, _mcb = lambda a, f, c, /: a.append((f, c or copy_context())), copy_and_clear, list; remove_done_callback, remove_async_callback, remove_noargs_callback, remove_noargs_async_callback = map(f, t)
36class D(A):
37 _acb, _icb, _mcb = lambda a, f, c, /: a.__setitem__(f, c or copy_context()), lambda d, /: tuple(d.items()), dict; remove_done_callback, remove_async_callback, remove_noargs_callback, remove_noargs_async_callback = map(lambda a, /: lambda self, f, a=a, /: 0 if getattr(self, a).pop(f, None) is None else 1, t)
38 def __init__(self, *a, **k): super().__init__(*a, **k); self._callbacks = {}
39 def add_done_callback(self, f, /, *, context=None):
40 if self._state == 'PENDING': type(self)._acb(self._callbacks, f, context)
41 else: self._loop.call_soon(f, self, context=context)
[docs]
42class TimeAwareFuture(B, Future): ...
[docs]
43class TimeAwareTask(B, Task): ...
[docs]
44class AsyncCallbacksFuture(C, _PyFuture): ...
[docs]
45class AsyncCallbacksTask(C, _PyTask): ...
[docs]
46class TimeAwareAsyncCallbacksFuture(C, B, _PyFuture): ...
[docs]
47class TimeAwareAsyncCallbacksTask(C, B, _PyTask): ...
[docs]
48class UniqueCallbacksFuture(D, _PyFuture): ...
[docs]
49class UniqueCallbacksTask(D, _PyTask): ...
[docs]
50class TimeAwareUniqueCallbacksFuture(D, B, _PyFuture): ...
[docs]
51class TimeAwareUniqueCallbacksTask(D, B, _PyTask): ...
52del f, t, A, B, C, D