"""Thread-safe iterator utilities.""" import threading from enum import Enum, auto from typing import Self class ThreadSafeIterableIteratorStatus(Enum): """Async Iterator Status.""" PENDING = auto() ACTIVE = auto() DONE = auto() ERROR = auto() class ThreadSafeIterableIterator[R]: """A thread-safe iterator wrapper that maintains state. Wraps a standard iterator to make it safe for concurrent access and provides state management (PENDING, ACTIVE, DONE, ERROR). This allows multiple threads to consume from the same iterator safely. The iterator lazily starts (transitions from PENDING to ACTIVE) on the first call to __next__. """ def __init__(self) -> None: """Initialize the thread-safe iterator in PENDING state.""" self._exception: Exception | None = None self._lock = threading.Lock() self._status = ThreadSafeIterableIteratorStatus.PENDING def __iter__(self) -> Self: """Return self as the iterator.""" return self def __next__(self) -> R: """Get the next item from the iterator in a thread-safe manner. Returns: R: The next item from the underlying source. Raises: StopIteration: When the source is exhausted. Exception: If an error occurred during iteration or in a previous step. """ with self._lock: if self._status == ThreadSafeIterableIteratorStatus.DONE: raise StopIteration if self._status == ThreadSafeIterableIteratorStatus.ERROR: raise self._exception # type: ignore[misc] if self._status == ThreadSafeIterableIteratorStatus.PENDING: self._status = ThreadSafeIterableIteratorStatus.ACTIVE self._start() try: return self._next() except StopIteration: self._status = ThreadSafeIterableIteratorStatus.DONE self._destroy() raise except Exception as e: self._status = ThreadSafeIterableIteratorStatus.ERROR self._exception = e self._destroy() raise def _destroy(self) -> None: """Clean up resources when iteration completes or fails.""" pass def _next(self) -> R: raise NotImplementedError def _start(self) -> None: """Prepare the iterator source (lazy initialization).""" pass