from typing import Self, ClassVar

intptr = int

def malloc(size: int) -> intptr: ...
def free(ptr: intptr) -> None: ...

def memcpy(dst: intptr, src: intptr, n: int) -> None: ...
def memset(s: intptr, c: int, n: int) -> None: ...
def memcmp(s1: intptr, s2: intptr, n: int) -> int: ...

def read_cstr(p: intptr) -> str: ...
def read_bytes(p: intptr, n: int) -> bytes: ...
def write_cstr(p: intptr, data: str) -> None: ...
def write_bytes(p: intptr, data: bytes) -> None: ...

class Memory:
    size: ClassVar[int]

class _BuiltinMemory[T](Memory):
    value: T

    def __new__(cls, value: T | None = None) -> None: ...
    @staticmethod
    def read(p: intptr, offset: int) -> T: ...
    @staticmethod
    def write(p: intptr, offset: int, value: T) -> None: ...
    @classmethod
    def array(cls, length: int) -> Self: ...

    def __getitem__(self, index: int) -> T: ...
    def __setitem__(self, index: int, value: T) -> None: ...

class Char(_BuiltinMemory[int]): ...
class UChar(_BuiltinMemory[int]): ...
class Short(_BuiltinMemory[int]): ...
class UShort(_BuiltinMemory[int]): ...
class Int(_BuiltinMemory[int]): ...
class UInt(_BuiltinMemory[int]): ...
class Long(_BuiltinMemory[int]): ...
class ULong(_BuiltinMemory[int]): ...
class LongLong(_BuiltinMemory[int]): ...
class ULongLong(_BuiltinMemory[int]): ...

class Float(_BuiltinMemory[float]): ...
class Double(_BuiltinMemory[float]): ...
class Pointer(_BuiltinMemory[intptr]): ...
class Bool(_BuiltinMemory[bool]): ...

Int8: _BuiltinMemory[int]
UInt8: _BuiltinMemory[int]
Int16: _BuiltinMemory[int]
UInt16: _BuiltinMemory[int]
Int32: _BuiltinMemory[int]
UInt32: _BuiltinMemory[int]
Int64: _BuiltinMemory[int]
UInt64: _BuiltinMemory[int]
SizeT: _BuiltinMemory[int]

IntptrT: _BuiltinMemory[int]
UintptrT: _BuiltinMemory[int]

def addressof(obj: Memory) -> intptr: ...
def sizeof(obj: type[Memory]) -> int: ...

