from typing import Annotated, overload

import numpy
from numpy.typing import NDArray


def get_is_valid(array: Annotated[NDArray, dict(writable=False)] | None) -> bool: ...

def get_shape(array: Annotated[NDArray, dict(writable=False)]) -> list: ...

def get_size(array: NDArray | None) -> int: ...

def get_itemsize(array: NDArray | None) -> int: ...

def get_nbytes(array: NDArray | None) -> int: ...

def get_stride(array: NDArray, i: int) -> int: ...

def check_shape_ptr(arg: NDArray, /) -> bool: ...

def check_stride_ptr(arg: NDArray, /) -> bool: ...

def check_float(arg: NDArray, /) -> bool: ...

def check_bool(arg: NDArray, /) -> bool: ...

def pass_float32(array: NDArray[numpy.float32]) -> None: ...

def pass_float32_const(array: Annotated[NDArray[numpy.float32], dict(writable=False)]) -> None: ...

def pass_complex64(array: NDArray[numpy.complex64]) -> None: ...

def pass_complex64_const(array: Annotated[NDArray[numpy.complex64], dict(writable=False)]) -> None: ...

def pass_uint32(array: NDArray[numpy.uint32]) -> None: ...

def pass_bool(array: NDArray[numpy.bool_]) -> None: ...

def pass_float32_shaped(array: Annotated[NDArray[numpy.float32], dict(shape=(3, None, 4))]) -> None: ...

def pass_float32_shaped_ordered(array: Annotated[NDArray[numpy.float32], dict(shape=(None, None, 4), order='C')]) -> None: ...

def check_rw_by_value(arg: NDArray, /) -> bool: ...

def check_ro_by_value_ro(arg: Annotated[NDArray, dict(writable=False)], /) -> bool: ...

def check_rw_by_value_float64(arg: Annotated[NDArray[numpy.float64], dict(shape=(None,))], /) -> bool: ...

def check_ro_by_value_const_float64(arg: Annotated[NDArray[numpy.float64], dict(shape=(None,), writable=False)], /) -> bool: ...

def check_rw_by_const_ref(arg: NDArray, /) -> bool: ...

def check_ro_by_const_ref_ro(arg: Annotated[NDArray, dict(writable=False)], /) -> bool: ...

def check_rw_by_const_ref_float64(arg: Annotated[NDArray[numpy.float64], dict(shape=(None,))], /) -> bool: ...

def check_ro_by_const_ref_const_float64(arg: Annotated[NDArray[numpy.float64], dict(shape=(None,), writable=False)], /) -> bool: ...

def check_rw_by_rvalue_ref(arg: NDArray, /) -> bool: ...

def check_ro_by_rvalue_ref_ro(arg: Annotated[NDArray, dict(writable=False)], /) -> bool: ...

def check_rw_by_rvalue_ref_float64(arg: Annotated[NDArray[numpy.float64], dict(shape=(None,))], /) -> bool: ...

def check_ro_by_rvalue_ref_const_float64(arg: Annotated[NDArray[numpy.float64], dict(shape=(None,), writable=False)], /) -> bool: ...

@overload
def check_order(arg: Annotated[NDArray, dict(order='C')], /) -> str: ...

@overload
def check_order(arg: Annotated[NDArray, dict(order='F')], /) -> str: ...

@overload
def check_order(arg: NDArray, /) -> str: ...

def make_contig(arg: Annotated[NDArray, dict(order='C')], /) -> Annotated[NDArray, dict(order='C')]: ...

@overload
def check_device(arg: Annotated[NDArray, dict(device='cpu')], /) -> str: ...

@overload
def check_device(arg: Annotated[NDArray, dict(device='cuda')], /) -> str: ...

@overload
def initialize(arg: Annotated[NDArray[numpy.uint8], dict(shape=(10), device='cpu')], /) -> None: ...

@overload
def initialize(arg: Annotated[NDArray[numpy.float32], dict(shape=(10), device='cpu')], /) -> None: ...

@overload
def initialize(arg: Annotated[NDArray[numpy.float32], dict(shape=(10, None), device='cpu')], /) -> None: ...

def noimplicit(array: Annotated[NDArray[numpy.float32], dict(shape=(2, 2), order='C')]) -> int: ...

def implicit(array: Annotated[NDArray[numpy.float32], dict(shape=(2, 2), order='C')]) -> int: ...

def inspect_ndarray(arg: NDArray, /) -> None: ...

def process(arg: Annotated[NDArray[numpy.uint8], dict(shape=(None, None, 3), order='C', device='cpu')], /) -> None: ...

def destruct_count() -> int: ...

def return_no_framework() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4))]: ...

def passthrough(arg: NDArray, /) -> NDArray: ...

def passthrough_copy(arg: NDArray, /) -> NDArray: ...

def passthrough_arg_none(arg: NDArray | None) -> NDArray: ...

def ret_numpy() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4))]: ...

def ret_numpy_const_ref() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4), order='C', writable=False)]: ...

def ret_numpy_const_ref_f() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4), order='F', writable=False)]: ...

def ret_numpy_const() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4), writable=False)]: ...

def ret_pytorch() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4))]: ...

def ret_memview() -> memoryview[dtype=float64, shape=(2, 4)]: ...

def ret_array_api() -> ArrayLike[dtype=float64, shape=(2, 4)]: ...

def ret_array_scalar() -> NDArray[numpy.float32]: ...

def noop_3d_c_contig(arg: Annotated[NDArray[numpy.float32], dict(shape=(None, None, None), order='C')], /) -> None: ...

def noop_2d_f_contig(arg: Annotated[NDArray[numpy.float32], dict(shape=(None, None), order='F')], /) -> None: ...

def accept_rw(arg: Annotated[NDArray[numpy.float32], dict(shape=(2))], /) -> float: ...

def accept_ro(arg: Annotated[NDArray[numpy.float32], dict(shape=(2), writable=False)], /) -> float: ...

def check(arg: object, /) -> bool: ...

def accept_np_both_true_contig_a(arg: Annotated[NDArray[numpy.float32], dict(shape=(2, 1), order='A')], /) -> float: ...

def accept_np_both_true_contig_c(arg: Annotated[NDArray[numpy.float32], dict(shape=(2, 1), order='C')], /) -> float: ...

def accept_np_both_true_contig_f(arg: Annotated[NDArray[numpy.float32], dict(shape=(2, 1), order='F')], /) -> float: ...

class Cls:
    def __init__(self) -> None: ...

    def f1(self) -> NDArray[numpy.float32]: ...

    def f2(self) -> NDArray[numpy.float32]: ...

    def f1_ri(self) -> NDArray[numpy.float32]: ...

    def f2_ri(self) -> NDArray[numpy.float32]: ...

    def f3_ri(self, arg: object, /) -> NDArray[numpy.float32]: ...

def fill_view_1(x: NDArray) -> None: ...

def fill_view_2(x: Annotated[NDArray[numpy.float32], dict(shape=(None, None), device='cpu')]) -> None: ...

def fill_view_3(x: Annotated[NDArray[numpy.float32], dict(shape=(3, 4), order='C', device='cpu')]) -> None: ...

def fill_view_4(x: Annotated[NDArray[numpy.float32], dict(shape=(3, 4), order='F', device='cpu')]) -> None: ...

def fill_view_5(x: Annotated[NDArray[numpy.complex64], dict(shape=(2, 2), order='C', device='cpu')]) -> None: ...

def fill_view_6(x: Annotated[NDArray[numpy.complex64], dict(shape=(2, 2), order='C', device='cpu')]) -> None: ...

def ret_numpy_half() -> Annotated[NDArray[numpy.float16], dict(shape=(2, 4))]: ...

def cast(arg: bool, /) -> NDArray: ...

@overload
def set_item(arg0: Annotated[NDArray[numpy.float64], dict(shape=(None,), order='C')], arg1: int, /) -> None: ...

@overload
def set_item(arg0: Annotated[NDArray[numpy.complex128], dict(shape=(None,), order='C')], arg1: int, /) -> None: ...

def test_implicit_conversion(arg: Annotated[NDArray, dict(order='C', device='cpu', writable=False)]) -> Annotated[NDArray, dict(order='C', device='cpu', writable=False)]: ...

def ret_infer_c() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4), order='C')]: ...

def ret_infer_f() -> Annotated[NDArray[numpy.float32], dict(shape=(2, 4), order='F')]: ...

class Matrix4f:
    def __init__(self) -> None: ...

    def data(self) -> Annotated[NDArray[numpy.float32], dict(shape=(4, 4), order='F')]: ...

    def data_ref(self) -> Annotated[NDArray[numpy.float32], dict(shape=(4, 4), order='F')]: ...

    def data_copy(self) -> Annotated[NDArray[numpy.float32], dict(shape=(4, 4), order='F')]: ...

def ret_from_stack_1() -> object: ...

def ret_from_stack_2() -> Annotated[NDArray[numpy.float32], dict(shape=(3))]: ...

class Wrapper:
    def __init__(self, arg: NDArray[numpy.float32], /) -> None: ...

    @property
    def value(self) -> NDArray[numpy.float32]: ...

    @value.setter
    def value(self, arg: NDArray[numpy.float32], /) -> None: ...

class MyArray:
    def __init__(self) -> None: ...

    def mutate(self) -> None: ...

    def __dlpack__(self, **kwargs) -> object: ...

    def __dlpack_device__(self) -> tuple[int, int]: ...

    def array_api(self) -> ArrayLike[dtype=float64]: ...
