pumpkin-api-py 0.1.0.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. pumpkin_api/__init__.py +139 -0
  2. pumpkin_api/app.py +8 -0
  3. pumpkin_api/build.py +35 -0
  4. pumpkin_api/wit/componentize_py_async_support/__init__.py +529 -0
  5. pumpkin_api/wit/componentize_py_async_support/futures.py +93 -0
  6. pumpkin_api/wit/componentize_py_async_support/streams.py +189 -0
  7. pumpkin_api/wit/componentize_py_runtime.pyi +34 -0
  8. pumpkin_api/wit/componentize_py_types.py +19 -0
  9. pumpkin_api/wit/poll_loop.py +440 -0
  10. pumpkin_api/wit/wit_world/__init__.py +70 -0
  11. pumpkin_api/wit/wit_world/exports/__init__.py +19 -0
  12. pumpkin_api/wit/wit_world/exports/metadata.py +22 -0
  13. pumpkin_api/wit/wit_world/imports/__init__.py +0 -0
  14. pumpkin_api/wit/wit_world/imports/command.py +539 -0
  15. pumpkin_api/wit/wit_world/imports/common.py +213 -0
  16. pumpkin_api/wit/wit_world/imports/context.py +70 -0
  17. pumpkin_api/wit/wit_world/imports/entity.py +84 -0
  18. pumpkin_api/wit/wit_world/imports/event.py +434 -0
  19. pumpkin_api/wit/wit_world/imports/gui.py +61 -0
  20. pumpkin_api/wit/wit_world/imports/i18n.py +35 -0
  21. pumpkin_api/wit/wit_world/imports/logging.py +30 -0
  22. pumpkin_api/wit/wit_world/imports/permission.py +71 -0
  23. pumpkin_api/wit/wit_world/imports/player.py +350 -0
  24. pumpkin_api/wit/wit_world/imports/scheduler.py +44 -0
  25. pumpkin_api/wit/wit_world/imports/scoreboard.py +95 -0
  26. pumpkin_api/wit/wit_world/imports/server.py +75 -0
  27. pumpkin_api/wit/wit_world/imports/text.py +89 -0
  28. pumpkin_api/wit/wit_world/imports/world.py +215 -0
  29. pumpkin_api/wit_files/command.wit +189 -0
  30. pumpkin_api/wit_files/common.wit +201 -0
  31. pumpkin_api/wit_files/componentize_py_async_support/__init__.py +529 -0
  32. pumpkin_api/wit_files/componentize_py_async_support/futures.py +93 -0
  33. pumpkin_api/wit_files/componentize_py_async_support/streams.py +189 -0
  34. pumpkin_api/wit_files/componentize_py_runtime.pyi +34 -0
  35. pumpkin_api/wit_files/componentize_py_types.py +19 -0
  36. pumpkin_api/wit_files/context.wit +33 -0
  37. pumpkin_api/wit_files/entity.wit +36 -0
  38. pumpkin_api/wit_files/event.wit +311 -0
  39. pumpkin_api/wit_files/gui.wit +38 -0
  40. pumpkin_api/wit_files/i18n.wit +21 -0
  41. pumpkin_api/wit_files/log.wit +14 -0
  42. pumpkin_api/wit_files/metadata.wit +15 -0
  43. pumpkin_api/wit_files/permission.wit +46 -0
  44. pumpkin_api/wit_files/player.wit +172 -0
  45. pumpkin_api/wit_files/plugin.wit +61 -0
  46. pumpkin_api/wit_files/poll_loop.py +440 -0
  47. pumpkin_api/wit_files/scheduler.wit +24 -0
  48. pumpkin_api/wit_files/scoreboard.wit +72 -0
  49. pumpkin_api/wit_files/server.wit +41 -0
  50. pumpkin_api/wit_files/text.wit +41 -0
  51. pumpkin_api/wit_files/wit_world/__init__.py +70 -0
  52. pumpkin_api/wit_files/wit_world/exports/__init__.py +19 -0
  53. pumpkin_api/wit_files/wit_world/exports/metadata.py +22 -0
  54. pumpkin_api/wit_files/wit_world/imports/__init__.py +0 -0
  55. pumpkin_api/wit_files/wit_world/imports/command.py +539 -0
  56. pumpkin_api/wit_files/wit_world/imports/common.py +213 -0
  57. pumpkin_api/wit_files/wit_world/imports/context.py +70 -0
  58. pumpkin_api/wit_files/wit_world/imports/entity.py +84 -0
  59. pumpkin_api/wit_files/wit_world/imports/event.py +434 -0
  60. pumpkin_api/wit_files/wit_world/imports/gui.py +61 -0
  61. pumpkin_api/wit_files/wit_world/imports/i18n.py +35 -0
  62. pumpkin_api/wit_files/wit_world/imports/logging.py +30 -0
  63. pumpkin_api/wit_files/wit_world/imports/permission.py +71 -0
  64. pumpkin_api/wit_files/wit_world/imports/player.py +350 -0
  65. pumpkin_api/wit_files/wit_world/imports/scheduler.py +44 -0
  66. pumpkin_api/wit_files/wit_world/imports/scoreboard.py +95 -0
  67. pumpkin_api/wit_files/wit_world/imports/server.py +75 -0
  68. pumpkin_api/wit_files/wit_world/imports/text.py +89 -0
  69. pumpkin_api/wit_files/wit_world/imports/world.py +215 -0
  70. pumpkin_api/wit_files/world.wit +169 -0
  71. pumpkin_api_py-0.1.0.dev0.dist-info/METADATA +58 -0
  72. pumpkin_api_py-0.1.0.dev0.dist-info/RECORD +75 -0
  73. pumpkin_api_py-0.1.0.dev0.dist-info/WHEEL +4 -0
  74. pumpkin_api_py-0.1.0.dev0.dist-info/entry_points.txt +2 -0
  75. pumpkin_api_py-0.1.0.dev0.dist-info/licenses/LICENSE +677 -0
@@ -0,0 +1,529 @@
1
+ import asyncio
2
+ import componentize_py_runtime
3
+ import subprocess
4
+
5
+ from os import PathLike
6
+ from socket import AddressFamily, AddressInfo, SocketKind, socket
7
+ from concurrent.futures import Executor
8
+ from componentize_py_types import Result, Ok, Err
9
+ from dataclasses import dataclass
10
+ from typing import Any, Optional, TypeVar, TypeVarTuple, Callable, IO, Literal, cast
11
+ from contextvars import ContextVar, Context
12
+ from collections.abc import Coroutine, Awaitable, Sequence
13
+ from asyncio.protocols import BaseProtocol
14
+ from asyncio.transports import Transport, WriteTransport, DatagramTransport, SubprocessTransport, ReadTransport
15
+ from asyncio.base_events import Server
16
+
17
+ try:
18
+ from ssl import SSLContext
19
+ except:
20
+ pass
21
+
22
+ @dataclass
23
+ class _FutureState:
24
+ waitable_set: int | None
25
+ futures: dict[int, Any]
26
+ handles: list[asyncio.Handle]
27
+ pending_count: int
28
+
29
+ class _ReturnCode:
30
+ COMPLETED = 0
31
+ DROPPED = 1
32
+ CANCELLED = 2
33
+
34
+ class _CallbackCode:
35
+ EXIT = 0
36
+ YIELD = 1
37
+ WAIT = 2
38
+ POLL = 3
39
+
40
+ class _Event:
41
+ NONE = 0
42
+ SUBTASK = 1
43
+ STREAM_READ = 2
44
+ STREAM_WRITE = 3
45
+ FUTURE_READ = 4
46
+ FUTURE_WRITE = 5
47
+ CANCELLED = 6
48
+
49
+ class _Status:
50
+ STARTING = 0
51
+ STARTED = 1
52
+ RETURNED = 2
53
+ START_CANCELLED = 3
54
+ RETURN_CANCELLED = 4
55
+
56
+ _T = TypeVar("_T")
57
+ _Ts = TypeVarTuple("_Ts")
58
+ _ProtocolT = TypeVar("_ProtocolT", bound=BaseProtocol)
59
+
60
+ async def _noop() -> None:
61
+ pass
62
+
63
+ class _Loop(asyncio.AbstractEventLoop):
64
+ def __init__(self) -> None:
65
+ self.running: bool = False
66
+ self.exception: Optional[Any] = None
67
+
68
+ def poll(self, future_state: _FutureState) -> None:
69
+ while True:
70
+ handles = future_state.handles
71
+ future_state.handles = []
72
+ for handle in handles:
73
+ if not handle._cancelled:
74
+ handle._run()
75
+
76
+ if self.exception is not None:
77
+ raise self.exception
78
+
79
+ if len(handles) == 0 and len(future_state.handles) == 0:
80
+ return
81
+
82
+ def get_debug(self) -> bool:
83
+ return False
84
+
85
+ def is_running(self) -> bool:
86
+ return self.running
87
+
88
+ def is_closed(self) -> bool:
89
+ return not self.running
90
+
91
+ def stop(self) -> None:
92
+ self.running = False
93
+
94
+ def close(self) -> None:
95
+ self.running = False
96
+
97
+ def shutdown_asyncgens(self) -> Coroutine[Any, Any, None]:
98
+ return _noop()
99
+
100
+ def call_exception_handler(self, context: dict[str, Any]) -> None:
101
+ self.exception = context.get('exception', None)
102
+
103
+ def call_soon(self,
104
+ callback: Callable[[*_Ts], object],
105
+ *args: *_Ts,
106
+ context: Context | None = None) -> asyncio.Handle:
107
+ global _future_state
108
+
109
+ if context is not None:
110
+ future_state = context[_future_state]
111
+ handle = asyncio.Handle(callback, args, self, context)
112
+ future_state.handles.append(handle)
113
+ return handle
114
+ else:
115
+ raise AssertionError
116
+
117
+ def create_task(self, coroutine: Coroutine[Any, Any, _T], name: str | None = None, context: Context | None = None) -> asyncio.Task[_T]:
118
+ return asyncio.Task(coroutine, loop=self, context=context)
119
+
120
+ def create_future(self) -> asyncio.Future[Any]:
121
+ return asyncio.Future(loop=self)
122
+
123
+ # The remaining methods should be irrelevant for our purposes and thus unimplemented
124
+
125
+ def run_until_complete(self, future: Awaitable[_T]) -> _T:
126
+ raise NotImplementedError
127
+
128
+ def run_forever(self) -> None:
129
+ raise NotImplementedError
130
+
131
+ async def shutdown_default_executor(self) -> None:
132
+ raise NotImplementedError
133
+
134
+ def call_later(self,
135
+ delay: float,
136
+ callback: Callable[[*_Ts], object],
137
+ *args: *_Ts,
138
+ context: Context | None = None) -> asyncio.TimerHandle:
139
+ raise NotImplementedError
140
+
141
+ def call_at(self,
142
+ when: float,
143
+ callback: Callable[[*_Ts], object],
144
+ *args: *_Ts,
145
+ context: Context | None = None) -> asyncio.TimerHandle:
146
+ raise NotImplementedError
147
+
148
+ def time(self) -> float:
149
+ raise NotImplementedError
150
+
151
+ def call_soon_threadsafe(self,
152
+ callback: Callable[[*_Ts], object],
153
+ *args: *_Ts,
154
+ context: Context | None = None) -> asyncio.Handle:
155
+ raise NotImplementedError
156
+
157
+ def run_in_executor(self,
158
+ executor: Executor | None,
159
+ func: Callable[[*_Ts], _T],
160
+ *args: *_Ts) -> asyncio.Future[_T]:
161
+ raise NotImplementedError
162
+
163
+ def set_default_executor(self, executor: Executor) -> None:
164
+ raise NotImplementedError
165
+
166
+ async def getaddrinfo(
167
+ self,
168
+ host: bytes | str | None,
169
+ port: bytes | str | int | None,
170
+ *,
171
+ family: int = 0,
172
+ type: int = 0,
173
+ proto: int = 0,
174
+ flags: int = 0,
175
+ ) -> list[tuple[AddressFamily, SocketKind, int, str, tuple[str, int] | tuple[str, int, int, int]]]:
176
+ raise NotImplementedError
177
+
178
+ async def getnameinfo(self,
179
+ sockaddr: tuple[str, int] | tuple[str, int, int, int],
180
+ flags: int = 0) -> tuple[str, str]:
181
+ raise NotImplementedError
182
+
183
+ async def create_connection(
184
+ self,
185
+ protocol_factory: Callable[[], _ProtocolT],
186
+ host: str | None = ...,
187
+ port: int | None = ...,
188
+ *,
189
+ ssl: bool | SSLContext | None = None,
190
+ family: int = 0,
191
+ proto: int = 0,
192
+ flags: int = 0,
193
+ sock: socket | None = None,
194
+ local_addr: tuple[str, int] | None = None,
195
+ server_hostname: str | None = None,
196
+ ssl_handshake_timeout: float | None = None,
197
+ ssl_shutdown_timeout: float | None = None,
198
+ happy_eyeballs_delay: float | None = None,
199
+ interleave: int | None = None,
200
+ ) -> tuple[Transport, _ProtocolT]:
201
+ raise NotImplementedError
202
+
203
+ async def create_server(
204
+ self,
205
+ protocol_factory: Callable[[], BaseProtocol],
206
+ host: str | Sequence[str] | None = None,
207
+ port: int | None = None,
208
+ *,
209
+ family: int = AddressFamily.AF_UNSPEC,
210
+ flags: int = AddressInfo.AI_PASSIVE,
211
+ sock: socket | None = ...,
212
+ backlog: int = 100,
213
+ ssl: bool | SSLContext | None = None,
214
+ reuse_address: bool | None = None,
215
+ reuse_port: bool | None = None,
216
+ keep_alive: bool | None = None,
217
+ ssl_handshake_timeout: float | None = None,
218
+ ssl_shutdown_timeout: float | None = None,
219
+ start_serving: bool = True,
220
+ ) -> Server:
221
+ raise NotImplementedError
222
+
223
+ async def sendfile(self,
224
+ transport: WriteTransport,
225
+ file: IO[bytes],
226
+ offset: int = 0,
227
+ count: int | None = None,
228
+ *,
229
+ fallback: bool = True
230
+ ) -> int:
231
+ raise NotImplementedError
232
+
233
+ async def start_tls(
234
+ self,
235
+ transport: WriteTransport,
236
+ protocol: BaseProtocol,
237
+ sslcontext: SSLContext,
238
+ *,
239
+ server_side: bool = False,
240
+ server_hostname: str | None = None,
241
+ ssl_handshake_timeout: float | None = None,
242
+ ssl_shutdown_timeout: float | None = None,
243
+ ) -> Transport | None:
244
+ raise NotImplementedError
245
+
246
+ async def create_unix_connection(
247
+ self,
248
+ protocol_factory: Callable[[], _ProtocolT],
249
+ path: str | None = None,
250
+ *,
251
+ ssl: bool | SSLContext | None = None,
252
+ sock: socket | None = None,
253
+ server_hostname: str | None = None,
254
+ ssl_handshake_timeout: float | None = None,
255
+ ssl_shutdown_timeout: float | None = None,
256
+ ) -> tuple[Transport, _ProtocolT]:
257
+ raise NotImplementedError
258
+
259
+ async def create_unix_server(
260
+ self,
261
+ protocol_factory: Callable[[], BaseProtocol],
262
+ path: str | PathLike[str] | None = None,
263
+ *,
264
+ sock: socket | None = None,
265
+ backlog: int = 100,
266
+ ssl: bool | SSLContext | None = None,
267
+ ssl_handshake_timeout: float | None = None,
268
+ ssl_shutdown_timeout: float | None = None,
269
+ start_serving: bool = True,
270
+ ) -> Server:
271
+ raise NotImplementedError
272
+
273
+ async def connect_accepted_socket(
274
+ self,
275
+ protocol_factory: Callable[[], _ProtocolT],
276
+ sock: socket,
277
+ *,
278
+ ssl: bool | SSLContext | None = None,
279
+ ssl_handshake_timeout: float | None = None,
280
+ ssl_shutdown_timeout: float | None = None,
281
+ ) -> tuple[Transport, _ProtocolT]:
282
+ raise NotImplementedError
283
+
284
+ async def create_datagram_endpoint(
285
+ self,
286
+ protocol_factory: Callable[[], _ProtocolT],
287
+ local_addr: tuple[str, int] | str | None = None,
288
+ remote_addr: tuple[str, int] | str | None = None,
289
+ *,
290
+ family: int = 0,
291
+ proto: int = 0,
292
+ flags: int = 0,
293
+ reuse_address: bool | None = None,
294
+ reuse_port: bool | None = None,
295
+ allow_broadcast: bool | None = None,
296
+ sock: socket | None = None,
297
+ ) -> tuple[DatagramTransport, _ProtocolT]:
298
+ raise NotImplementedError
299
+
300
+ async def connect_read_pipe(self,
301
+ protocol_factory: Callable[[], _ProtocolT],
302
+ pipe: Any) -> tuple[ReadTransport, _ProtocolT]:
303
+ raise NotImplementedError
304
+
305
+ async def connect_write_pipe(self,
306
+ protocol_factory: Callable[[], _ProtocolT],
307
+ pipe: Any) -> tuple[WriteTransport, _ProtocolT]:
308
+ raise NotImplementedError
309
+
310
+ async def subprocess_shell(
311
+ self,
312
+ protocol_factory: Callable[[], _ProtocolT],
313
+ cmd: bytes | str,
314
+ *,
315
+ stdin: int | IO[Any] | None = -1,
316
+ stdout: int | IO[Any] | None = -1,
317
+ stderr: int | IO[Any] | None = -1,
318
+ universal_newlines: Literal[False] = False,
319
+ shell: Literal[True] = True,
320
+ bufsize: Literal[0] = 0,
321
+ encoding: None = None,
322
+ errors: None = None,
323
+ text: Literal[False] | None = None,
324
+ **kwargs: Any,
325
+ ) -> tuple[SubprocessTransport, _ProtocolT]:
326
+ raise NotImplementedError
327
+
328
+ async def subprocess_exec(
329
+ self,
330
+ protocol_factory: Callable[[], _ProtocolT],
331
+ program: Any,
332
+ *args: Any,
333
+ stdin: int | IO[Any] | None = -1,
334
+ stdout: int | IO[Any] | None = -1,
335
+ stderr: int | IO[Any] | None = -1,
336
+ universal_newlines: Literal[False] = False,
337
+ shell: Literal[False] = False,
338
+ bufsize: Literal[0] = 0,
339
+ encoding: None = None,
340
+ errors: None = None,
341
+ **kwargs: Any,
342
+ ) -> tuple[SubprocessTransport, _ProtocolT]:
343
+ raise NotImplementedError
344
+
345
+ def add_reader(self, fd: Any, callback: Callable[[*_Ts], Any], *args: *_Ts) -> None:
346
+ raise NotImplementedError
347
+
348
+ def remove_reader(self, fd: Any) -> bool:
349
+ raise NotImplementedError
350
+
351
+ def add_writer(self, fd: Any, callback: Callable[[*_Ts], Any], *args: *_Ts) -> None:
352
+ raise NotImplementedError
353
+
354
+ def remove_writer(self, fd: Any) -> bool:
355
+ raise NotImplementedError
356
+
357
+ async def sock_recv(self, sock: socket, nbytes: int) -> bytes:
358
+ raise NotImplementedError
359
+
360
+ async def sock_recv_into(self, sock: socket, buf: Any) -> int:
361
+ raise NotImplementedError
362
+
363
+ async def sock_recvfrom(self, sock: socket, bufsize: int) -> tuple[bytes, Any]:
364
+ raise NotImplementedError
365
+
366
+ async def sock_recvfrom_into(self, sock: socket, buf: Any, nbytes: int = 0) -> tuple[int, Any]:
367
+ raise NotImplementedError
368
+
369
+ async def sock_sendall(self, sock: socket, data: Any) -> None:
370
+ raise NotImplementedError
371
+
372
+ async def sock_sendto(self, sock: socket, data: Any, address: Any) -> int:
373
+ raise NotImplementedError
374
+
375
+ async def sock_connect(self, sock: socket, address: Any) -> None:
376
+ raise NotImplementedError
377
+
378
+ async def sock_accept(self, sock: socket) -> tuple[socket, Any]:
379
+ raise NotImplementedError
380
+
381
+ async def sock_sendfile(
382
+ self,
383
+ sock: socket,
384
+ file: IO[bytes],
385
+ offset: int = 0,
386
+ count: int | None = None,
387
+ *,
388
+ fallback: bool | None = None
389
+ ) -> int:
390
+ raise NotImplementedError
391
+
392
+ def add_signal_handler(self, sig: int, callback: Callable[[*_Ts], object], *args: *_Ts) -> None:
393
+ raise NotImplementedError
394
+
395
+ def remove_signal_handler(self, sig: int) -> bool:
396
+ raise NotImplementedError
397
+
398
+ def set_task_factory(self, factory: Any | None) -> None:
399
+ raise NotImplementedError
400
+
401
+ def get_task_factory(self) -> None:
402
+ raise NotImplementedError
403
+
404
+ def get_exception_handler(self) -> None:
405
+ raise NotImplementedError
406
+
407
+ def set_exception_handler(self, handler: Any | None) -> None:
408
+ raise NotImplementedError
409
+
410
+ def default_exception_handler(self, context: dict[str, Any]) -> None:
411
+ raise NotImplementedError
412
+
413
+ def set_debug(self, enabled: bool) -> None:
414
+ raise NotImplementedError
415
+
416
+ _future_state: ContextVar[_FutureState] = ContextVar("_future_state")
417
+ _loop = _Loop()
418
+ asyncio.set_event_loop(_loop)
419
+ _loop.running = True
420
+ asyncio.events._set_running_loop(_loop)
421
+
422
+ def _set_future_state(future_state: _FutureState) -> None:
423
+ global _future_state
424
+
425
+ _future_state.set(future_state)
426
+
427
+ async def _return_result(export_index: int, borrows: int, coroutine: Any) -> None:
428
+ global _future_state
429
+
430
+ try:
431
+ try:
432
+ result: Result[Any, Any] = Ok(await coroutine)
433
+ except Err as e:
434
+ result = e
435
+
436
+ componentize_py_runtime.call_task_return(export_index, borrows, result)
437
+ except Exception as e:
438
+ _loop.exception = e
439
+
440
+ assert _future_state.get().pending_count > 0
441
+ _future_state.get().pending_count -= 1
442
+
443
+ def first_poll(export_index: int, borrows: int, coroutine: Any) -> int:
444
+ context = Context()
445
+ future_state = _FutureState(None, {}, [], 1)
446
+ context.run(_set_future_state, future_state)
447
+ asyncio.create_task(_return_result(export_index, borrows, coroutine), context=context)
448
+ return _poll(future_state)
449
+
450
+ def _poll(future_state: _FutureState) -> int:
451
+ global _loop
452
+
453
+ _loop.poll(future_state)
454
+
455
+ if future_state.pending_count == 0:
456
+ if future_state.waitable_set is not None:
457
+ componentize_py_runtime.waitable_set_drop(future_state.waitable_set)
458
+
459
+ return _CallbackCode.EXIT
460
+ else:
461
+ waitable_set = future_state.waitable_set
462
+ assert waitable_set is not None
463
+ componentize_py_runtime.context_set(future_state)
464
+ return _CallbackCode.WAIT | (waitable_set << 4)
465
+
466
+ def callback(event0: int, event1: int, event2: int) -> int:
467
+ future_state = componentize_py_runtime.context_get()
468
+ componentize_py_runtime.context_set(None)
469
+
470
+ match event0:
471
+ case _Event.NONE:
472
+ pass
473
+ case _Event.SUBTASK:
474
+ match event2:
475
+ case _Status.STARTING:
476
+ raise AssertionError
477
+ case _Status.STARTED:
478
+ pass
479
+ case _Status.RETURNED:
480
+ componentize_py_runtime.waitable_join(event1, 0)
481
+ componentize_py_runtime.subtask_drop(event1)
482
+ future_state.futures.pop(event1).set_result(event2)
483
+ case _:
484
+ # todo
485
+ raise NotImplementedError
486
+ case _Event.STREAM_READ | _Event.STREAM_WRITE | _Event.FUTURE_READ | _Event.FUTURE_WRITE:
487
+ componentize_py_runtime.waitable_join(event1, 0)
488
+ future_state.futures.pop(event1).set_result(event2)
489
+ case _:
490
+ # todo
491
+ raise NotImplementedError
492
+
493
+ return _poll(future_state)
494
+
495
+ async def await_result[T](result: Result[T, tuple[int, int]]) -> T:
496
+ global _loop
497
+ global _future_state
498
+
499
+ if isinstance(result, Ok):
500
+ return result.value
501
+ else:
502
+ future_state = _future_state.get()
503
+ waitable, promise = result.value
504
+ future = _loop.create_future()
505
+ future_state.futures[waitable] = future
506
+
507
+ if future_state.waitable_set is None:
508
+ future_state.waitable_set = componentize_py_runtime.waitable_set_new()
509
+ componentize_py_runtime.waitable_join(waitable, future_state.waitable_set)
510
+
511
+ return cast(T, componentize_py_runtime.promise_get_result(await future, promise))
512
+
513
+ async def _wrap_spawned(coroutine: Any) -> None:
514
+ global _future_state
515
+
516
+ try:
517
+ await coroutine
518
+ except Exception as e:
519
+ _loop.exception = e
520
+
521
+ assert _future_state.get().pending_count > 0
522
+ _future_state.get().pending_count -= 1
523
+
524
+ def spawn(coroutine: Any) -> None:
525
+ global _future_state
526
+
527
+ _future_state.get().pending_count += 1
528
+
529
+ asyncio.create_task(_wrap_spawned(coroutine))
@@ -0,0 +1,93 @@
1
+ import componentize_py_runtime
2
+ import componentize_py_async_support
3
+ import weakref
4
+
5
+ from typing import TypeVar, Generic, cast, Self, Any, Callable
6
+ from types import TracebackType
7
+ from componentize_py_async_support import _ReturnCode
8
+
9
+ T = TypeVar('T')
10
+
11
+ class FutureReader(Generic[T]):
12
+ def __init__(self, type_: int, handle: int):
13
+ self.type_ = type_
14
+ self.handle: int | None = handle
15
+ self.finalizer = weakref.finalize(self, componentize_py_runtime.future_drop_readable, type_, handle)
16
+
17
+ async def read(self) -> T:
18
+ self.finalizer.detach()
19
+ handle = self.handle
20
+ self.handle = None
21
+ if handle is not None:
22
+ result = await componentize_py_async_support.await_result(
23
+ componentize_py_runtime.future_read(self.type_, handle)
24
+ )
25
+ componentize_py_runtime.future_drop_readable(self.type_, handle)
26
+ return cast(T, result)
27
+ else:
28
+ raise AssertionError
29
+
30
+ def __enter__(self) -> Self:
31
+ return self
32
+
33
+ def __exit__(self,
34
+ exc_type: type[BaseException] | None,
35
+ exc_value: BaseException | None,
36
+ traceback: TracebackType | None) -> bool | None:
37
+ if self.handle is not None:
38
+ self.finalizer.detach()
39
+ handle = self.handle
40
+ self.handle = None
41
+ componentize_py_runtime.future_drop_readable(self.type_, handle)
42
+
43
+ return None
44
+
45
+ async def write(type_: int, handle: int, value: Any) -> None:
46
+ await componentize_py_async_support.await_result(
47
+ componentize_py_runtime.future_write(type_, handle, value)
48
+ )
49
+ componentize_py_runtime.future_drop_writable(type_, handle)
50
+
51
+ def write_default(type_: int, handle: int, default: Callable[[], Any]) -> None:
52
+ componentize_py_async_support.spawn(write(type_, handle, default()))
53
+
54
+ class FutureWriter(Generic[T]):
55
+ def __init__(self, type_: int, handle: int, default: Callable[[], T]):
56
+ self.type_ = type_
57
+ self.handle: int | None = handle
58
+ self.default = default
59
+ self.finalizer = weakref.finalize(self, write_default, type_, handle, default)
60
+
61
+ async def write(self, value: T) -> bool:
62
+ self.finalizer.detach()
63
+ handle = self.handle
64
+ self.handle = None
65
+ if handle is not None:
66
+ code, _ = await componentize_py_async_support.await_result(
67
+ componentize_py_runtime.future_write(self.type_, handle, value)
68
+ )
69
+ componentize_py_runtime.future_drop_writable(self.type_, handle)
70
+ match code:
71
+ case _ReturnCode.COMPLETED:
72
+ return True
73
+ case _ReturnCode.DROPPED:
74
+ return False
75
+ case _ReturnCode.CANCELLED:
76
+ # todo
77
+ raise NotImplementedError
78
+ case _:
79
+ raise AssertionError
80
+ else:
81
+ raise AssertionError
82
+
83
+ def __enter__(self) -> Self:
84
+ return self
85
+
86
+ def __exit__(self,
87
+ exc_type: type[BaseException] | None,
88
+ exc_value: BaseException | None,
89
+ traceback: TracebackType | None) -> bool | None:
90
+ if self.handle is not None:
91
+ componentize_py_async_support.spawn(self.write(self.default()))
92
+
93
+ return None