# This file was generated by stubgen-pyx v0.2.6 from cuda_core/cuda/core/_stream.pyx

from __future__ import annotations

from dataclasses import dataclass
from typing import Protocol

import cuda.bindings.driver
import cython
from cuda.core._context import Context
from cuda.core._device import Device
from cuda.core._device_resources import DeviceResources
from cuda.core._event import Event, EventOptions
from cuda.core.graph import GraphBuilder


@dataclass
class StreamOptions:
    """Customizable :obj:`~_stream.Stream` options.

    Attributes
    ----------
    nonblocking : bool, optional
        Stream does not synchronize with the NULL stream. (Default to True)
    priority : int, optional
        Stream priority where lower number represents a
        higher priority. (Default to lowest priority)

    """
    nonblocking: cython.bint = True
    priority: int | None = None

class IsStreamType(Protocol):

    def __cuda_stream__(self) -> tuple[int, int]:
        """
        For any Python object that is meant to be interpreted as a CUDA stream, the intent
        can be communicated by implementing this protocol that returns a 2-tuple: The protocol
        version number (currently ``0``) and the address of ``cudaStream_t``. Both values
        should be Python `int`.
        """

class Stream:
    """Represent a queue of GPU operations that are executed in a specific order.

    Applications use streams to control the order of execution for
    GPU work. Work within a single stream are executed sequentially.
    Whereas work across multiple streams can be further controlled
    using stream priorities and :obj:`~_event.Event` managements.

    Advanced users can utilize default streams for enforce complex
    implicit synchronization behaviors.

    Directly creating a :obj:`~_stream.Stream` is not supported due to ambiguity.
    New streams should instead be created through a :obj:`~_device.Device`
    object, or created directly through using an existing handle
    using Stream.from_handle().
    """

    def close(self):
        """Destroy the stream.

        Releases the stream handle. For owned streams, this destroys the
        underlying CUDA stream. For borrowed streams, this releases the
        reference and allows the Python owner to be GC'd.
        """

    def __init__(self, *args, **kwargs) -> None:
        ...

    @classmethod
    def _legacy_default(cls) -> Stream:
        """Return the legacy default stream (supports subclassing)."""

    @classmethod
    def _per_thread_default(cls) -> Stream:
        """Return the per-thread default stream (supports subclassing)."""

    @classmethod
    def _init(cls, obj: IsStreamType | None=None, options: object=None, device_id: int | None=None, ctx: Context | None=None) -> Stream:
        ...

    def __cuda_stream__(self) -> tuple[int, int]:
        """Return an instance of a __cuda_stream__ protocol."""

    def __hash__(self) -> int:
        ...

    def __eq__(self, other: object) -> bool:
        ...

    def __repr__(self) -> str:
        ...

    @property
    def handle(self) -> cuda.bindings.driver.CUstream:
        """Return the underlying ``CUstream`` object.

        .. caution::

            This handle is a Python object. To get the memory address of the underlying C
            handle, call ``int(Stream.handle)``.
        """

    @property
    def is_nonblocking(self) -> bool:
        """Return True if this is a nonblocking stream, otherwise False."""

    @property
    def priority(self) -> int:
        """Return the stream priority."""

    def sync(self) -> None:
        """Synchronize the stream."""

    def record(self, event: Event | None=None, options: EventOptions | None=None) -> Event:
        """Record an event onto the stream.

        Creates an :obj:`~_event.Event` object (or reuses the given one) by
        recording on the stream.

        Parameters
        ----------
        event : :obj:`~_event.Event`, optional
            Optional event object to be reused for recording.
        options : :obj:`EventOptions`, optional
            Customizable dataclass for event creation options.

        Returns
        -------
        :obj:`~_event.Event`
            Newly created event object.

        Note
        ----
        A default stream (:obj:`LEGACY_DEFAULT_STREAM` or
        :obj:`PER_THREAD_DEFAULT_STREAM`) carries no context of its own; it
        refers to whichever context is current, so a newly created event is
        associated with the current context at call time.

        """

    def wait(self, event_or_stream: Event | Stream) -> None:
        """Wait for a CUDA event or a CUDA stream.

        Waiting for an event or a stream establishes a stream order.

        If a :obj:`~_stream.Stream` is provided, then wait until the stream's
        work is completed. This is done by recording a new :obj:`~_event.Event`
        on the stream and then waiting on it.

        Parameters
        ----------
        event_or_stream : :obj:`~_event.Event` | :obj:`~_stream.Stream`
            The event or stream to wait for. Objects supporting the
            ``__cuda_stream__`` protocol are also accepted and treated as
            streams.

        """

    @property
    def device(self) -> Device:
        """Return the :obj:`~_device.Device` singleton associated with this stream.

        Note
        ----
        A default stream (:obj:`LEGACY_DEFAULT_STREAM` or
        :obj:`PER_THREAD_DEFAULT_STREAM`) carries no context of its own; it
        refers to whichever context is current, so this returns the device for
        the current context at call time.

        For a created stream, the current context on the device may differ from
        this stream's context. That case occurs when a different CUDA context is
        set current after the stream is created.

        """

    @property
    def context(self) -> Context:
        """Return the :obj:`~_context.Context` associated with this stream.

        Note
        ----
        A default stream (:obj:`LEGACY_DEFAULT_STREAM` or
        :obj:`PER_THREAD_DEFAULT_STREAM`) carries no context of its own; it
        refers to whichever context is current, so this returns the current
        context at call time.

        """

    @property
    def resources(self) -> DeviceResources:
        """Query the hardware resources provisioned for this stream's context.

        For streams created from a green context, returns the resources
        that context was provisioned with. For streams on the primary
        context, returns the full device resources.

        Note
        ----
        A default stream (:obj:`LEGACY_DEFAULT_STREAM` or
        :obj:`PER_THREAD_DEFAULT_STREAM`) carries no context of its own; it
        refers to whichever context is current, so this queries the current
        context at call time.

        """

    @staticmethod
    def from_handle(handle) -> Stream:
        """Create a new :obj:`~_stream.Stream` object from a foreign stream handle.

        Uses a cudaStream_t pointer address represented as a Python int
        to create a new :obj:`~_stream.Stream` object.

        Note
        ----
        Stream lifetime is not managed, foreign object must remain
        alive while this stream is active.

        Parameters
        ----------
        handle : int
            Stream handle representing the address of a foreign
            stream object.

        Returns
        -------
        :obj:`~_stream.Stream`
            Newly created stream object.

        """

    def create_graph_builder(self) -> GraphBuilder:
        """Create a new :obj:`~graph.GraphBuilder` object.

        The new graph builder will be associated with this stream.

        Returns
        -------
        :obj:`~graph.GraphBuilder`
            Newly created graph builder object.

        """
__all__ = ['LEGACY_DEFAULT_STREAM', 'PER_THREAD_DEFAULT_STREAM', 'Stream', 'StreamOptions']
LEGACY_DEFAULT_STREAM: Stream = Stream._legacy_default()
PER_THREAD_DEFAULT_STREAM: Stream = Stream._per_thread_default()

def default_stream() -> Stream:
    """Return the default CUDA :obj:`~_stream.Stream`.

    The type of default stream returned depends on if the environment
    variable CUDA_PYTHON_CUDA_PER_THREAD_DEFAULT_STREAM is set.

    If set, returns a per-thread default stream. Otherwise returns
    the legacy stream.

    """

def Stream_accept(arg, allow_stream_protocol: bool=False) -> Stream:
    ...