from . import _ffi as ffi
import ctypes
from typing import Optional, Any
from wasmtime import MemoryType, WasmtimeError, Engine, Managed
from ._store import Storelike



class SharedMemory(Managed["ctypes._Pointer[ffi.wasmtime_sharedmemory_t]"]):
    def __init__(self, engine: Engine, ty: MemoryType):
        """
        Creates a new shared memory in `store` with the given `ty`
        """

        sharedmemory_ptr = ctypes.POINTER(ffi.wasmtime_sharedmemory_t)()
        error = ffi.wasmtime_sharedmemory_new(engine.ptr(), ty.ptr(), ctypes.byref(sharedmemory_ptr))
        if error:
            raise WasmtimeError._from_ptr(error)
        self._set_ptr(sharedmemory_ptr)

    def _delete(self, ptr: "ctypes._Pointer[ffi.wasmtime_sharedmemory_t]") -> None:
        ffi.wasmtime_sharedmemory_delete(ptr)

    @classmethod
    def _from_ptr(cls, ptr: "ctypes._Pointer[ffi.wasmtime_sharedmemory_t]") -> "SharedMemory":
        if not isinstance(ptr, ctypes.POINTER(ffi.wasmtime_sharedmemory_t)):
            raise TypeError("wrong shared memory pointer type provided to _from_ptr")
        
        ty: "SharedMemory" = cls.__new__(cls)
        ty._set_ptr(ptr)
        return ty

    def type(self) -> MemoryType:
        """
        Gets the type of this memory as a `MemoryType`
        """

        ptr = ffi.wasmtime_sharedmemory_type(self.ptr())
        return MemoryType._from_ptr(ptr, None)

    def grow(self, delta: int) -> int:
        """
        Grows this memory by the given number of pages
        """

        if delta < 0:
            raise WasmtimeError("cannot grow by negative amount")
        prev = ctypes.c_uint64(0)
        error = ffi.wasmtime_sharedmemory_grow(self.ptr(), delta, ctypes.byref(prev))
        if error:
            raise WasmtimeError._from_ptr(error)
        return prev.value

    def size(self) -> int:
        """
        Returns the size, in WebAssembly pages, of this shared memory.
        """

        return ffi.wasmtime_sharedmemory_size(ctypes.byref(self.ptr()))

    def data_ptr(self) -> "ctypes._Pointer[ctypes.c_ubyte]":
        """
        Returns the raw pointer in memory where this wasm shared memory lives.

        Remember that all accesses to wasm shared memory should be bounds-checked
        against the `data_len` method.
        """
        return ffi.wasmtime_sharedmemory_data(self.ptr())

    def data_len(self) -> int:
        """
        Returns the raw byte length of this memory.
        """

        return ffi.wasmtime_sharedmemory_data_size(self.ptr())

    def _as_extern(self) -> ffi.wasmtime_extern_t:
        union = ffi.wasmtime_extern_union(sharedmemory=ctypes.pointer(self.ptr()))
        return ffi.wasmtime_extern_t(ffi.WASMTIME_EXTERN_SHAREDMEMORY, union)
