from enum import Enum
from typing import SupportsBytes

from numpy.typing import NDArray

__all__ = ["DsetType", "Stream", "Data"]

class MemoryView(SupportsBytes):  # Note: Supports buffer protocol.
    base: "Array"
    size: int
    itemsize: int
    nbytes: int
    ndim: int
    shape: tuple[int, ...]
    strides: tuple[int, ...]
    suboffsets: tuple[int, ...]
    T: "MemoryView"

    def copy(self) -> "MemoryView": ...
    def copy_fortran(self) -> "MemoryView": ...
    def is_c_contig(self) -> bool: ...
    def is_f_contig(self) -> bool: ...

class Array:
    memview: MemoryView

    def __len__(self) -> int: ...
    def __getitem__(self, key: int | slice) -> bytes: ...
    def __setitem__(self, key: int | slice, item: bytes): ...

class DsetType(int, Enum):
    T_F32 = ...
    T_F64 = ...
    T_C32 = ...
    T_C64 = ...
    T_I8 = ...
    T_I16 = ...
    T_I32 = ...
    T_I64 = ...
    T_U8 = ...
    T_U16 = ...
    T_U32 = ...
    T_U64 = ...
    T_STR = ...
    T_OBJ = ...

class Data:
    def __init__(self, other: "Data" | None = None) -> None: ...
    def innerjoin(self, key: str, other: "Data") -> "Data": ...
    def totalsz(self) -> int: ...
    def ncol(self) -> int: ...
    def nrow(self) -> int: ...
    def key(self, index: int) -> str: ...
    def type(self, field: str) -> DsetType: ...
    def has(self, field: str) -> bool: ...
    def addrows(self, num: int) -> None: ...
    def addcol_scalar(self, field: str, dtype: int) -> None: ...
    def addcol_array(self, field: str, dtype: int, shape: tuple[int, ...]) -> None: ...
    def getshp(self, colkey: str) -> tuple[int, ...]: ...
    def getbuf(self, colkey: str) -> Array | None: ...
    def getstr(self, col: str, index: int) -> bytes: ...
    def tocstrs(self, col: str) -> bool: ...
    def topystrs(self, col: str) -> bool: ...
    def stralloc(self, val: str) -> int: ...
    def dump(self) -> Array: ...
    def dumpstrheap(self) -> Array: ...
    def setstrheap(self, heap: bytes) -> None: ...
    def defrag(self, realloc_smaller: bool) -> None: ...
    def dumptxt(self, dump_data: bool = False) -> None: ...
    def handle(self) -> int: ...

class Stream:
    def __init__(self, data: Data) -> None: ...
    def cast_objs_to_strs(self) -> None: ...
    def stralloc_col(self, col: str) -> Array | None: ...
    def compress_col(self, col: str) -> Array: ...
    def compress_numpy(self, arr: NDArray) -> Array: ...
    def compress(self, arr: Array) -> Array: ...
    def decompress_col(self, col: str, data: bytes) -> Array: ...
    def decompress_numpy(self, data: bytes, arr: NDArray) -> Array: ...
    def decompress(self, data: bytes, outptr: int = 0) -> Array: ...
