# This file was generated by stubgen-pyx v0.2.19 from cuda_core/cuda/core/_memory/_copy_ops.pyx

from collections.abc import Sequence

from cuda.core._memory._buffer import Buffer
from cuda.core._memory._copy_enums import CopyOptions
from cuda.core._stream import Stream

_SINGLE_COPY_HINT = 'Buffer.copy_to / Buffer.copy_from'

def _normalize_copy_options(options: CopyOptions | Sequence[CopyOptions] | None, n: int) -> tuple[CopyOptions, ...]:
    """Expand ``options`` to exactly one :class:`CopyOptions` per copy.

    ``None`` and a scalar broadcast; a sequence pairs by index and must
    already have length ``n``.

    Internal, but deliberately importable: options are hints that change
    how the driver stages a transfer and never the bytes it produces, so
    this expansion (and the run encoding applied to it) is the only
    observable evidence that a scalar reached every copy.
    """
def copy_batch(stream: Stream, srcs: Sequence[Buffer], dsts: Sequence[Buffer], *, options: CopyOptions | Sequence[CopyOptions] | None=None) -> None:
    """Copy a batch of buffers asynchronously.

    Source buffer and destination buffer sizes must match. For a single
    buffer, use :meth:`Buffer.copy_to` or :meth:`Buffer.copy_from`.

    The driver provides no graph-node form of ``cuMemcpyBatchAsync``, so
    this cannot be captured into a graph. Both passing a
    :class:`~graph.GraphBuilder` and passing its underlying
    :attr:`~graph.GraphBuilder.stream` while capture is active are
    rejected. Build graph copies with
    :meth:`graph.GraphNode.memcpy` or per-buffer :meth:`Buffer.copy_to`.

    Parameters
    ----------
    stream : :class:`~_stream.Stream`
        Stream for the asynchronous copy. First positional and required
        (mirrors :func:`launch`). Does not accept a capturing stream
        (including a :class:`~graph.GraphBuilder`'s underlying stream); use
        :meth:`graph.GraphNode.memcpy` or per-buffer
        :meth:`Buffer.copy_to` to build copies into a graph. Does not accept
        ``LEGACY_DEFAULT_STREAM``, which ``cuMemcpyBatchAsync`` rejects
        outright; ``PER_THREAD_DEFAULT_STREAM`` is a real stream to the
        driver and is accepted.
    srcs : Sequence[:class:`Buffer`]
        Source buffers. Must be a sequence, not a single Buffer.
    dsts : Sequence[:class:`Buffer`]
        Destination buffers. Must match ``len(srcs)``.
    options : :class:`CopyOptions` | Sequence[:class:`CopyOptions`] | None
        Per-copy options. A single value applies to every copy; a
        sequence pairs by index and must match ``len(srcs)``. ``None``
        uses stream-ordered defaults.

    Raises
    ------
    ValueError
        If lengths or sizes mismatch.
    TypeError
        If a single Buffer is passed instead of a sequence, if
        ``LEGACY_DEFAULT_STREAM`` is passed, or if the stream is currently
        in graph capture mode.
    RuntimeError
        If any copy requests ``src_access_order=DURING_API_CALL`` and the
        native ``cuMemcpyBatchAsync`` path is unavailable (see Notes): the
        per-copy ``cuMemcpyAsync`` fallback reads the source in stream
        order only, which cannot honor that guarantee.

    Notes
    -----
    Batching through ``cuMemcpyBatchAsync`` requires all three of:
    ``cuda.core`` built against CUDA 13 headers, ``cuda.bindings`` 13.0 or
    newer, and a driver reporting CUDA 13.0 or newer
    (``cuDriverGetVersion() >= 13000``). ``cuda.bindings`` binds only the
    CUDA 13.0 revision of the entry point, so a driver that predates it is
    refused even where it implements the earlier CUDA 12.8 signature.

    The driver may execute batch items concurrently and in any order.
    A batch must therefore not contain copies where the source range of
    one copy overlaps the destination range of another; such aliasing
    produces undefined results. Detecting overlaps at runtime is
    impractical; callers are responsible for ensuring no aliasing exists.

    On pre-CUDA 13 installs the copies fall back to a Python-level loop
    over ``cuMemcpyAsync``, so the potential performance benefit of
    asynchronous batched copies is not realized. ``src_access_order`` values
    of ``STREAM`` and ``ANY`` are silently ignored on the fallback path
    (stream-ordered access already satisfies both); ``DURING_API_CALL``
    raises ``RuntimeError`` instead, since silently downgrading it to
    stream-ordered access would let a caller reuse the source buffer before
    the real read happens.

    """
