sonolus.py 0.3.4__py3-none-any.whl → 0.4.0__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.

Potentially problematic release.


This version of sonolus.py might be problematic. Click here for more details.

Files changed (63) hide show
  1. sonolus/backend/excepthook.py +30 -0
  2. sonolus/backend/finalize.py +15 -1
  3. sonolus/backend/ops.py +4 -0
  4. sonolus/backend/optimize/allocate.py +5 -5
  5. sonolus/backend/optimize/constant_evaluation.py +124 -19
  6. sonolus/backend/optimize/copy_coalesce.py +15 -12
  7. sonolus/backend/optimize/dead_code.py +7 -6
  8. sonolus/backend/optimize/dominance.py +2 -2
  9. sonolus/backend/optimize/flow.py +54 -8
  10. sonolus/backend/optimize/inlining.py +137 -30
  11. sonolus/backend/optimize/liveness.py +2 -2
  12. sonolus/backend/optimize/optimize.py +15 -1
  13. sonolus/backend/optimize/passes.py +11 -3
  14. sonolus/backend/optimize/simplify.py +137 -8
  15. sonolus/backend/optimize/ssa.py +47 -13
  16. sonolus/backend/place.py +5 -4
  17. sonolus/backend/utils.py +24 -0
  18. sonolus/backend/visitor.py +260 -17
  19. sonolus/build/cli.py +47 -19
  20. sonolus/build/compile.py +12 -5
  21. sonolus/build/engine.py +70 -1
  22. sonolus/build/level.py +3 -3
  23. sonolus/build/project.py +2 -2
  24. sonolus/script/archetype.py +12 -9
  25. sonolus/script/array.py +23 -18
  26. sonolus/script/array_like.py +26 -29
  27. sonolus/script/bucket.py +1 -1
  28. sonolus/script/containers.py +22 -26
  29. sonolus/script/debug.py +20 -43
  30. sonolus/script/effect.py +1 -1
  31. sonolus/script/globals.py +3 -3
  32. sonolus/script/instruction.py +2 -2
  33. sonolus/script/internal/builtin_impls.py +155 -28
  34. sonolus/script/internal/constant.py +13 -3
  35. sonolus/script/internal/context.py +46 -15
  36. sonolus/script/internal/impl.py +9 -3
  37. sonolus/script/internal/introspection.py +8 -1
  38. sonolus/script/internal/native.py +2 -2
  39. sonolus/script/internal/range.py +8 -11
  40. sonolus/script/internal/simulation_context.py +1 -1
  41. sonolus/script/internal/transient.py +2 -2
  42. sonolus/script/internal/value.py +41 -3
  43. sonolus/script/interval.py +13 -13
  44. sonolus/script/iterator.py +38 -107
  45. sonolus/script/maybe.py +139 -0
  46. sonolus/script/num.py +17 -2
  47. sonolus/script/options.py +1 -1
  48. sonolus/script/particle.py +1 -1
  49. sonolus/script/project.py +24 -5
  50. sonolus/script/quad.py +15 -15
  51. sonolus/script/record.py +16 -12
  52. sonolus/script/runtime.py +22 -18
  53. sonolus/script/sprite.py +1 -1
  54. sonolus/script/stream.py +66 -82
  55. sonolus/script/transform.py +35 -34
  56. sonolus/script/values.py +10 -10
  57. sonolus/script/vec.py +21 -18
  58. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.0.dist-info}/METADATA +1 -1
  59. sonolus_py-0.4.0.dist-info/RECORD +93 -0
  60. sonolus_py-0.3.4.dist-info/RECORD +0 -92
  61. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.0.dist-info}/WHEEL +0 -0
  62. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.0.dist-info}/entry_points.txt +0 -0
  63. {sonolus_py-0.3.4.dist-info → sonolus_py-0.4.0.dist-info}/licenses/LICENSE +0 -0
sonolus/script/quad.py CHANGED
@@ -1,6 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
- from typing import Protocol, Self
3
+ from typing import Protocol
4
4
 
5
5
  from sonolus.script.record import Record
6
6
  from sonolus.script.values import zeros
@@ -57,7 +57,7 @@ class Quad(Record):
57
57
  """The center of the quad."""
58
58
  return (self.bl + self.tr + self.tl + self.br) / 4
59
59
 
60
- def translate(self, translation: Vec2, /) -> Self:
60
+ def translate(self, translation: Vec2, /) -> Quad:
61
61
  """Translate the quad by the given translation and return a new quad."""
62
62
  return Quad(
63
63
  bl=self.bl + translation,
@@ -66,7 +66,7 @@ class Quad(Record):
66
66
  br=self.br + translation,
67
67
  )
68
68
 
69
- def scale(self, factor: Vec2, /) -> Self:
69
+ def scale(self, factor: Vec2, /) -> Quad:
70
70
  """Scale the quad by the given factor about the origin and return a new quad."""
71
71
  return Quad(
72
72
  bl=self.bl * factor,
@@ -75,7 +75,7 @@ class Quad(Record):
75
75
  br=self.br * factor,
76
76
  )
77
77
 
78
- def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Self:
78
+ def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Quad:
79
79
  """Scale the quad by the given factor about the given pivot and return a new quad."""
80
80
  return Quad(
81
81
  bl=(self.bl - pivot) * factor + pivot,
@@ -84,7 +84,7 @@ class Quad(Record):
84
84
  br=(self.br - pivot) * factor + pivot,
85
85
  )
86
86
 
87
- def scale_centered(self, factor: Vec2, /) -> Self:
87
+ def scale_centered(self, factor: Vec2, /) -> Quad:
88
88
  """Scale the quad by the given factor about its center and return a new quad."""
89
89
  return Quad(
90
90
  bl=self.bl * factor,
@@ -93,7 +93,7 @@ class Quad(Record):
93
93
  br=self.br * factor,
94
94
  ).translate(self.center * (Vec2(1, 1) - factor))
95
95
 
96
- def rotate(self, angle: float, /) -> Self:
96
+ def rotate(self, angle: float, /) -> Quad:
97
97
  """Rotate the quad by the given angle about the origin and return a new quad.
98
98
 
99
99
  Args:
@@ -114,7 +114,7 @@ class Quad(Record):
114
114
  angle: float,
115
115
  /,
116
116
  pivot: Vec2,
117
- ) -> Self:
117
+ ) -> Quad:
118
118
  """Rotate the quad by the given angle about the given pivot and return a new quad.
119
119
 
120
120
  Args:
@@ -131,7 +131,7 @@ class Quad(Record):
131
131
  br=self.br.rotate_about(angle, pivot),
132
132
  )
133
133
 
134
- def rotate_centered(self, angle: float, /) -> Self:
134
+ def rotate_centered(self, angle: float, /) -> Quad:
135
135
  """Rotate the quad by the given angle about its center and return a new quad.
136
136
 
137
137
  Args:
@@ -142,7 +142,7 @@ class Quad(Record):
142
142
  """
143
143
  return self.rotate_about(angle, self.center)
144
144
 
145
- def permute(self, count: int = 1, /) -> Self:
145
+ def permute(self, count: int = 1, /) -> Quad:
146
146
  """Perform a cyclic permutation of the quad's vertices and return a new quad.
147
147
 
148
148
  On a square, this operation is equivalent to rotating the square counterclockwise 90 degrees `count` times.
@@ -269,7 +269,7 @@ class Rect(Record):
269
269
  br=self.br,
270
270
  )
271
271
 
272
- def translate(self, translation: Vec2, /) -> Self:
272
+ def translate(self, translation: Vec2, /) -> Rect:
273
273
  """Translate the rectangle by the given translation and return a new rectangle."""
274
274
  return Rect(
275
275
  t=self.t + translation.y,
@@ -278,7 +278,7 @@ class Rect(Record):
278
278
  l=self.l + translation.x,
279
279
  )
280
280
 
281
- def scale(self, factor: Vec2, /) -> Self:
281
+ def scale(self, factor: Vec2, /) -> Rect:
282
282
  """Scale the rectangle by the given factor about the origin and return a new rectangle."""
283
283
  return Rect(
284
284
  t=self.t * factor.y,
@@ -287,7 +287,7 @@ class Rect(Record):
287
287
  l=self.l * factor.x,
288
288
  )
289
289
 
290
- def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Self:
290
+ def scale_about(self, factor: Vec2, /, pivot: Vec2) -> Rect:
291
291
  """Scale the rectangle by the given factor about the given pivot and return a new rectangle."""
292
292
  return Rect(
293
293
  t=(self.t - pivot.y) * factor.y + pivot.y,
@@ -296,7 +296,7 @@ class Rect(Record):
296
296
  l=(self.l - pivot.x) * factor.x + pivot.x,
297
297
  )
298
298
 
299
- def scale_centered(self, factor: Vec2, /) -> Self:
299
+ def scale_centered(self, factor: Vec2, /) -> Rect:
300
300
  """Scale the rectangle by the given factor about its center and return a new rectangle."""
301
301
  return Rect(
302
302
  t=self.t * factor.y,
@@ -305,7 +305,7 @@ class Rect(Record):
305
305
  l=self.l * factor.x,
306
306
  ).translate(self.center * (Vec2(1, 1) - factor))
307
307
 
308
- def expand(self, expansion: Vec2, /) -> Self:
308
+ def expand(self, expansion: Vec2, /) -> Rect:
309
309
  """Expand the rectangle by the given amount and return a new rectangle."""
310
310
  return Rect(
311
311
  t=self.t + expansion.y,
@@ -314,7 +314,7 @@ class Rect(Record):
314
314
  l=self.l - expansion.x,
315
315
  )
316
316
 
317
- def shrink(self, shrinkage: Vec2, /) -> Self:
317
+ def shrink(self, shrinkage: Vec2, /) -> Rect:
318
318
  """Shrink the rectangle by the given amount and return a new rectangle."""
319
319
  return Rect(
320
320
  t=self.t - shrinkage.y,
sonolus/script/record.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import inspect
4
+ from abc import ABCMeta
4
5
  from collections.abc import Iterable
5
6
  from inspect import getmro
6
7
  from typing import Any, ClassVar, Self, TypeVar, dataclass_transform, get_origin
@@ -20,7 +21,7 @@ from sonolus.script.internal.value import BackingSource, DataValue, Value
20
21
  from sonolus.script.num import Num
21
22
 
22
23
 
23
- class RecordMeta(type):
24
+ class RecordMeta(ABCMeta):
24
25
  @meta_fn
25
26
  def __pos__[T](cls: type[T]) -> T:
26
27
  """Create a zero-initialized record instance."""
@@ -183,7 +184,7 @@ class Record(GenericValue, metaclass=RecordMeta):
183
184
  result = object.__new__(cls)
184
185
  result._value = {
185
186
  field.name: field.type._from_backing_source_(
186
- lambda offset, field_offset=field.offset: source((Num(offset) + Num(field_offset)).ir())
187
+ lambda offset, field_offset=field.offset: source((Num(offset) + Num(field_offset)).ir()) # type: ignore
187
188
  )
188
189
  for field in cls._fields
189
190
  }
@@ -234,10 +235,10 @@ class Record(GenericValue, metaclass=RecordMeta):
234
235
  def _get_(self) -> Self:
235
236
  return self
236
237
 
237
- def _set_(self, value: Self):
238
+ def _set_(self, value: Any):
238
239
  raise TypeError("Record does not support _set_")
239
240
 
240
- def _copy_from_(self, value: Self):
241
+ def _copy_from_(self, value: Any):
241
242
  value = self._accept_(value)
242
243
  for field in self._fields:
243
244
  field.__set__(self, field.__get__(value))
@@ -259,14 +260,14 @@ class Record(GenericValue, metaclass=RecordMeta):
259
260
  return result
260
261
 
261
262
  def __str__(self):
262
- return (
263
- f"{self.__class__.__name__}({', '.join(f'{field.name}={field.__get__(self)}' for field in self._fields)})"
264
- )
263
+ return f"{self.__class__.__name__}({
264
+ ', '.join(f'{field.name}={field.get_internal(self)}' for field in self._fields)
265
+ })"
265
266
 
266
267
  def __repr__(self):
267
- return (
268
- f"{self.__class__.__name__}({', '.join(f'{field.name}={field.__get__(self)!r}' for field in self._fields)})"
269
- )
268
+ return f"{self.__class__.__name__}({
269
+ ', '.join(f'{field.name}={field.get_internal(self)!r}' for field in self._fields)
270
+ })"
270
271
 
271
272
  @meta_fn
272
273
  def __eq__(self, other: Any) -> bool:
@@ -309,16 +310,19 @@ class Record(GenericValue, metaclass=RecordMeta):
309
310
 
310
311
 
311
312
  class _RecordField(SonolusDescriptor):
312
- def __init__(self, name: str, type_: type[Value], index: int, offset: int):
313
+ def __init__(self, name: str, type_: type[Value] | Any, index: int, offset: int):
313
314
  self.name = name
314
315
  self.type = type_
315
316
  self.index = index
316
317
  self.offset = offset
317
318
 
319
+ def get_internal(self, instance: Record) -> Value:
320
+ return instance._value[self.name]
321
+
318
322
  def __get__(self, instance: Record | None, owner=None):
319
323
  if instance is None:
320
324
  return self
321
- result = instance._value[self.name]._get_()
325
+ result = instance._value[self.name]._get_readonly_()
322
326
  if ctx():
323
327
  return result
324
328
  else:
sonolus/script/runtime.py CHANGED
@@ -698,7 +698,7 @@ class _TouchArray:
698
698
 
699
699
  @_runtime_skin_transform
700
700
  class _SkinTransform:
701
- value: Array[Array[float, 4], 4]
701
+ value: Array[Array[float, 4], 4] # type: ignore
702
702
 
703
703
  @property
704
704
  @meta_fn
@@ -719,7 +719,7 @@ class _SkinTransform:
719
719
 
720
720
  @_runtime_particle_transform
721
721
  class _ParticleTransform:
722
- value: Array[Array[float, 4], 4]
722
+ value: Array[Array[float, 4], 4] # type: ignore
723
723
 
724
724
  @property
725
725
  @meta_fn
@@ -857,25 +857,25 @@ def is_debug() -> bool:
857
857
  @meta_fn
858
858
  def is_play() -> bool:
859
859
  """Check if the game is running in play mode."""
860
- return ctx() and ctx().global_state.mode == Mode.PLAY
860
+ return bool(ctx() and ctx().global_state.mode == Mode.PLAY)
861
861
 
862
862
 
863
863
  @meta_fn
864
864
  def is_preview() -> bool:
865
865
  """Check if the game is running in preview mode."""
866
- return ctx() and ctx().global_state.mode == Mode.PREVIEW
866
+ return bool(ctx() and ctx().global_state.mode == Mode.PREVIEW)
867
867
 
868
868
 
869
869
  @meta_fn
870
870
  def is_watch() -> bool:
871
871
  """Check if the game is running in watch mode."""
872
- return ctx() and ctx().global_state.mode == Mode.WATCH
872
+ return bool(ctx() and ctx().global_state.mode == Mode.WATCH)
873
873
 
874
874
 
875
875
  @meta_fn
876
876
  def is_tutorial() -> bool:
877
877
  """Check if the game is running in tutorial mode."""
878
- return ctx() and ctx().global_state.mode == Mode.TUTORIAL
878
+ return bool(ctx() and ctx().global_state.mode == Mode.TUTORIAL)
879
879
 
880
880
 
881
881
  @meta_fn
@@ -884,7 +884,7 @@ def is_preprocessing() -> bool:
884
884
 
885
885
  Returns True if the current callback is one of preprocess, spawn_order, spawn_time, or despawn_time.
886
886
  """
887
- return ctx() and ctx().callback in {"preprocess", "spawnOrder", "spawnTime", "despawnTime"}
887
+ return bool(ctx() and ctx().callback in {"preprocess", "spawnOrder", "spawnTime", "despawnTime"})
888
888
 
889
889
 
890
890
  @meta_fn
@@ -1058,12 +1058,16 @@ def prev_time() -> float:
1058
1058
  def touches() -> ArrayLike[Touch]:
1059
1059
  """Get the current touches of the game."""
1060
1060
  if not ctx():
1061
- return Array[Touch, 0]()
1061
+ return Array[Touch, 0]() # type: ignore
1062
1062
  match ctx().global_state.mode:
1063
1063
  case Mode.PLAY:
1064
- return ArrayPointer[Touch](_PlayRuntimeUpdate.touch_count, ctx().blocks.RuntimeTouchArray, 0)
1064
+ return ArrayPointer[Touch]._raw(
1065
+ size=Num._accept_(_PlayRuntimeUpdate.touch_count),
1066
+ block=Num._accept_(ctx().blocks.RuntimeTouchArray),
1067
+ offset=Num._accept_(0),
1068
+ )
1065
1069
  case _:
1066
- return Array[Touch, 0]()
1070
+ return Array[Touch, 0]() # type: ignore
1067
1071
 
1068
1072
 
1069
1073
  @meta_fn
@@ -1098,24 +1102,24 @@ def navigation_direction() -> int:
1098
1102
 
1099
1103
  def skin_transform() -> Transform2d:
1100
1104
  """Get the global skin transform."""
1101
- return _SkinTransform.transform
1105
+ return _SkinTransform.transform # type: ignore
1102
1106
 
1103
1107
 
1104
1108
  @meta_fn
1105
1109
  def set_skin_transform(value: Transform2d):
1106
1110
  """Set the global skin transform."""
1107
- _SkinTransform.transform._copy_from_(value)
1111
+ _SkinTransform.transform._copy_from_(value) # type: ignore
1108
1112
 
1109
1113
 
1110
1114
  def particle_transform() -> Transform2d:
1111
1115
  """Get the global particle transform."""
1112
- return _ParticleTransform.transform
1116
+ return _ParticleTransform.transform # type: ignore
1113
1117
 
1114
1118
 
1115
1119
  @meta_fn
1116
1120
  def set_particle_transform(value: Transform2d):
1117
1121
  """Set the global particle transform."""
1118
- _ParticleTransform.transform._copy_from_(value)
1122
+ _ParticleTransform.transform._copy_from_(value) # type: ignore
1119
1123
 
1120
1124
 
1121
1125
  def background() -> Quad:
@@ -1142,12 +1146,12 @@ _runtime_ui = RuntimeUi()
1142
1146
 
1143
1147
  def runtime_ui() -> RuntimeUi:
1144
1148
  """Get the runtime UI configuration."""
1145
- return _runtime_ui
1149
+ return _runtime_ui # type: ignore
1146
1150
 
1147
1151
 
1148
1152
  def canvas() -> _PreviewRuntimeCanvas:
1149
1153
  """Get the preview canvas."""
1150
- return _PreviewRuntimeCanvas
1154
+ return _PreviewRuntimeCanvas # type: ignore
1151
1155
 
1152
1156
 
1153
1157
  def screen() -> Rect:
@@ -1157,9 +1161,9 @@ def screen() -> Rect:
1157
1161
 
1158
1162
  def level_score() -> _LevelScore:
1159
1163
  """Get the level score configuration."""
1160
- return _LevelScore
1164
+ return _LevelScore # type: ignore
1161
1165
 
1162
1166
 
1163
1167
  def level_life() -> _LevelLife:
1164
1168
  """Get the level life configuration."""
1165
- return _LevelLife
1169
+ return _LevelLife # type: ignore
sonolus/script/sprite.py CHANGED
@@ -267,7 +267,7 @@ def sprite(name: str) -> Any:
267
267
  return SkinSprite(name)
268
268
 
269
269
 
270
- type Skin = NewType("Skin", Any)
270
+ type Skin = NewType("Skin", Any) # type: ignore
271
271
 
272
272
 
273
273
  class RenderMode(StrEnum):
sonolus/script/stream.py CHANGED
@@ -13,6 +13,7 @@ from sonolus.script.internal.introspection import get_field_specifiers
13
13
  from sonolus.script.internal.native import native_function
14
14
  from sonolus.script.internal.value import BackingValue, Value
15
15
  from sonolus.script.iterator import SonolusIterator
16
+ from sonolus.script.maybe import Maybe, Nothing, Some
16
17
  from sonolus.script.num import Num
17
18
  from sonolus.script.record import Record
18
19
  from sonolus.script.runtime import prev_time, time
@@ -48,7 +49,7 @@ class _StreamDataField(SonolusDescriptor):
48
49
 
49
50
  def __get__(self, instance, owner):
50
51
  _check_can_read_or_write_stream()
51
- return self._get()._get_()
52
+ return self._get()._get_readonly_()
52
53
 
53
54
  def __set__(self, instance, value):
54
55
  _check_can_write_stream()
@@ -136,7 +137,7 @@ class _StreamBacking(BackingValue):
136
137
  id: Num
137
138
  index: Num
138
139
 
139
- def __init__(self, stream_id: int, index: Num):
140
+ def __init__(self, stream_id: int, index: Num | int | float):
140
141
  super().__init__()
141
142
  self.id = Num._accept_(stream_id)
142
143
  self.index = Num._accept_(index)
@@ -240,10 +241,10 @@ class Stream[T](Record):
240
241
  # We still need to store something to preserve the key, so this is a special case.
241
242
  _stream_set(self.offset, key, 0)
242
243
  else:
243
- for i, v in enumerate(value._to_list_()):
244
+ for i, v in enumerate(cast(Value, value)._to_list_()):
244
245
  _stream_set(self.offset + i, key, Num(v))
245
246
 
246
- def next_key(self, key: int | float) -> int:
247
+ def next_key(self, key: int | float) -> int | float:
247
248
  """Get the next key, or the key unchanged if it is the last key or the stream is empty.
248
249
 
249
250
  If the key is in the stream and there is a next key, returns the next key.
@@ -251,13 +252,13 @@ class Stream[T](Record):
251
252
  _check_can_read_stream()
252
253
  return _stream_get_next_key(self.offset, key)
253
254
 
254
- def next_key_or_default(self, key: int | float, default: int | float) -> int:
255
+ def next_key_or_default(self, key: int | float, default: int | float) -> int | float:
255
256
  """Get the next key, or the default value if there is no next key."""
256
257
  _check_can_read_stream()
257
258
  next_key = self.next_key(key)
258
259
  return next_key if next_key > key else default
259
260
 
260
- def previous_key(self, key: int | float) -> int:
261
+ def previous_key(self, key: int | float) -> int | float:
261
262
  """Get the previous key, or the key unchanged if it is the first key or the stream is empty.
262
263
 
263
264
  If the key is in the stream and there is a previous key, returns the previous key.
@@ -265,7 +266,7 @@ class Stream[T](Record):
265
266
  _check_can_read_stream()
266
267
  return _stream_get_previous_key(self.offset, key)
267
268
 
268
- def previous_key_or_default(self, key: int | float, default: int | float) -> int:
269
+ def previous_key_or_default(self, key: int | float, default: int | float) -> int | float:
269
270
  """Get the previous key, or the default value if there is no previous key."""
270
271
  _check_can_read_stream()
271
272
  previous_key = self.previous_key(key)
@@ -283,12 +284,12 @@ class Stream[T](Record):
283
284
  previous_key = self.previous_key(key)
284
285
  return previous_key < key
285
286
 
286
- def next_key_inclusive(self, key: int | float) -> int:
287
+ def next_key_inclusive(self, key: int | float) -> int | float:
287
288
  """Like `next_key`, but returns the key itself if it is in the stream."""
288
289
  _check_can_read_stream()
289
290
  return key if key in self else self.next_key(key)
290
291
 
291
- def previous_key_inclusive(self, key: int | float) -> int:
292
+ def previous_key_inclusive(self, key: int | float) -> int | float:
292
293
  """Like `previous_key`, but returns the key itself if it is in the stream."""
293
294
  _check_can_read_stream()
294
295
  return key if key in self else self.previous_key(key)
@@ -508,21 +509,20 @@ class StreamGroup[T, Size](Record):
508
509
  _check_can_read_or_write_stream()
509
510
  assert index in self
510
511
  # Size 0 elements still need 1 stream to preserve the key.
511
- return Stream[self.type_var_value(T)](max(1, sizeof(self.element_type())) * index + self.offset)
512
+ t = self.type_var_value(T)
513
+ return Stream[t](max(1, sizeof(self.element_type())) * index + self.offset)
512
514
 
513
515
 
514
516
  class _StreamAscIterator[T](Record, SonolusIterator[tuple[int | float, T]]):
515
517
  stream: Stream[T]
516
518
  current_key: int | float
517
519
 
518
- def has_next(self) -> bool:
519
- return self.current_key in self.stream
520
-
521
- def get(self) -> tuple[int | float, T]:
522
- return self.current_key, self.stream[self.current_key]
523
-
524
- def advance(self):
525
- self.current_key = self.stream.next_key_or_default(self.current_key, inf)
520
+ def next(self) -> Maybe[tuple[int | float, T]]:
521
+ if self.current_key in self.stream:
522
+ result = (self.current_key, self.stream[self.current_key])
523
+ self.current_key = self.stream.next_key_or_default(self.current_key, inf)
524
+ return Some(result)
525
+ return Nothing
526
526
 
527
527
 
528
528
  class _StreamBoundedAscIterator[T](Record, SonolusIterator[tuple[int | float, T]]):
@@ -530,42 +530,36 @@ class _StreamBoundedAscIterator[T](Record, SonolusIterator[tuple[int | float, T]
530
530
  current_key: int | float
531
531
  end_key: int | float
532
532
 
533
- def has_next(self) -> bool:
534
- return self.current_key in self.stream and self.current_key <= self.end_key
535
-
536
- def get(self) -> tuple[int | float, T]:
537
- return self.current_key, self.stream[self.current_key]
538
-
539
- def advance(self):
540
- self.current_key = self.stream.next_key_or_default(self.current_key, inf)
533
+ def next(self) -> Maybe[tuple[int | float, T]]:
534
+ if self.current_key in self.stream and self.current_key <= self.end_key:
535
+ result = (self.current_key, self.stream[self.current_key])
536
+ self.current_key = self.stream.next_key_or_default(self.current_key, inf)
537
+ return Some(result)
538
+ return Nothing
541
539
 
542
540
 
543
541
  class _StreamDescIterator[T](Record, SonolusIterator[tuple[int | float, T]]):
544
542
  stream: Stream[T]
545
543
  current_key: int | float
546
544
 
547
- def has_next(self) -> bool:
548
- return self.current_key in self.stream
549
-
550
- def get(self) -> tuple[int | float, T]:
551
- return self.current_key, self.stream[self.current_key]
552
-
553
- def advance(self):
554
- self.current_key = self.stream.previous_key_or_default(self.current_key, -inf)
545
+ def next(self) -> Maybe[tuple[int | float, T]]:
546
+ if self.current_key in self.stream:
547
+ result = (self.current_key, self.stream[self.current_key])
548
+ self.current_key = self.stream.previous_key_or_default(self.current_key, -inf)
549
+ return Some(result)
550
+ return Nothing
555
551
 
556
552
 
557
553
  class _StreamAscKeyIterator[T](Record, SonolusIterator[int | float]):
558
554
  stream: Stream[T]
559
555
  current_key: int | float
560
556
 
561
- def has_next(self) -> bool:
562
- return self.current_key in self.stream
563
-
564
- def get(self) -> int | float:
565
- return self.current_key
566
-
567
- def advance(self):
568
- self.current_key = self.stream.next_key_or_default(self.current_key, inf)
557
+ def next(self) -> Maybe[int | float]:
558
+ if self.current_key in self.stream:
559
+ result = self.current_key
560
+ self.current_key = self.stream.next_key_or_default(self.current_key, inf)
561
+ return Some(result)
562
+ return Nothing
569
563
 
570
564
 
571
565
  class _StreamBoundedAscKeyIterator[T](Record, SonolusIterator[int | float]):
@@ -573,42 +567,36 @@ class _StreamBoundedAscKeyIterator[T](Record, SonolusIterator[int | float]):
573
567
  current_key: int | float
574
568
  end_key: int | float
575
569
 
576
- def has_next(self) -> bool:
577
- return self.current_key in self.stream and self.current_key <= self.end_key
578
-
579
- def get(self) -> int | float:
580
- return self.current_key
581
-
582
- def advance(self):
583
- self.current_key = self.stream.next_key_or_default(self.current_key, inf)
570
+ def next(self) -> Maybe[int | float]:
571
+ if self.current_key in self.stream and self.current_key <= self.end_key:
572
+ result = self.current_key
573
+ self.current_key = self.stream.next_key_or_default(self.current_key, inf)
574
+ return Some(result)
575
+ return Nothing
584
576
 
585
577
 
586
578
  class _StreamDescKeyIterator[T](Record, SonolusIterator[int | float]):
587
579
  stream: Stream[T]
588
580
  current_key: int | float
589
581
 
590
- def has_next(self) -> bool:
591
- return self.current_key in self.stream
592
-
593
- def get(self) -> int | float:
594
- return self.current_key
595
-
596
- def advance(self):
597
- self.current_key = self.stream.previous_key_or_default(self.current_key, -inf)
582
+ def next(self) -> Maybe[int | float]:
583
+ if self.current_key in self.stream:
584
+ result = self.current_key
585
+ self.current_key = self.stream.previous_key_or_default(self.current_key, -inf)
586
+ return Some(result)
587
+ return Nothing
598
588
 
599
589
 
600
590
  class _StreamAscValueIterator[T](Record, SonolusIterator[T]):
601
591
  stream: Stream[T]
602
592
  current_key: int | float
603
593
 
604
- def has_next(self) -> bool:
605
- return self.current_key in self.stream
606
-
607
- def get(self) -> T:
608
- return self.stream[self.current_key]
609
-
610
- def advance(self):
611
- self.current_key = self.stream.next_key_or_default(self.current_key, inf)
594
+ def next(self) -> Maybe[T]:
595
+ if self.current_key in self.stream:
596
+ result = self.stream[self.current_key]
597
+ self.current_key = self.stream.next_key_or_default(self.current_key, inf)
598
+ return Some(result)
599
+ return Nothing
612
600
 
613
601
 
614
602
  class _StreamBoundedAscValueIterator[T](Record, SonolusIterator[T]):
@@ -616,28 +604,24 @@ class _StreamBoundedAscValueIterator[T](Record, SonolusIterator[T]):
616
604
  current_key: int | float
617
605
  end_key: int | float
618
606
 
619
- def has_next(self) -> bool:
620
- return self.current_key in self.stream and self.current_key <= self.end_key
621
-
622
- def get(self) -> T:
623
- return self.stream[self.current_key]
624
-
625
- def advance(self):
626
- self.current_key = self.stream.next_key_or_default(self.current_key, inf)
607
+ def next(self) -> Maybe[T]:
608
+ if self.current_key in self.stream and self.current_key <= self.end_key:
609
+ result = self.stream[self.current_key]
610
+ self.current_key = self.stream.next_key_or_default(self.current_key, inf)
611
+ return Some(result)
612
+ return Nothing
627
613
 
628
614
 
629
615
  class _StreamDescValueIterator[T](Record, SonolusIterator[T]):
630
616
  stream: Stream[T]
631
617
  current_key: int | float
632
618
 
633
- def has_next(self) -> bool:
634
- return self.current_key in self.stream
635
-
636
- def get(self) -> T:
637
- return self.stream[self.current_key]
638
-
639
- def advance(self):
640
- self.current_key = self.stream.previous_key_or_default(self.current_key, -inf)
619
+ def next(self) -> Maybe[T]:
620
+ if self.current_key in self.stream:
621
+ result = self.stream[self.current_key]
622
+ self.current_key = self.stream.previous_key_or_default(self.current_key, -inf)
623
+ return Some(result)
624
+ return Nothing
641
625
 
642
626
 
643
627
  @native_function(Op.StreamGetNextKey)