packages feed

wasmedge-hs-0.17.1.0: src/WasmEdge/Store.hs

{- |
Module      : WasmEdge.Store
Description : WasmEdge store context
Author      : Tushar Adhatrao <tusharadhatrao@gmail.com>
Copyright   : (c) 2026 Tushar Adhatrao
License     : MIT
Stability   : stable
-}
module WasmEdge.Store
  ( Store
  , createStore
  , deleteStore
  , withStore
  , findModule
  , listModules
  -- Internal
  , unsafeStorePtr
  , borrowStore
  ) where

import Control.Exception (bracket, throwIO)
import Control.Monad (forM)
import Data.Text (Text)
import Foreign.Marshal.Alloc (allocaBytes)
import Foreign.Ptr (FunPtr, Ptr, nullPtr, plusPtr)
import WasmEdge.Error
import WasmEdge.Internal.FFI.Execution
import WasmEdge.Internal.Ownership
import WasmEdge.Internal.Storable (stringSize)
import WasmEdge.Internal.Types
import WasmEdge.Internal.Utils (peekWasmString, withWasmString)
import WasmEdge.Module (ModuleInstance, borrowModule)

-- | WebAssembly runtime store context for module instances and exported definitions.
newtype Store = Store (OwnedCtx StoreTag)

-- | Create a new runtime 'Store'.
createStore :: IO Store
createStore = do
  p <- c_StoreCreate
  if p == nullPtr
    then throwIO $ WasmEdgeError ErrCategory_WASM 0 "WasmEdge_StoreCreate returned NULL"
    else Store <$> mkOwned (appFunPtr c_StoreDelete) p

-- | Delete a runtime 'Store'.
deleteStore :: Store -> IO ()
deleteStore (Store o) = finalizeOwned o

-- | Scoped runtime 'Store'.
withStore :: (Store -> IO a) -> IO a
withStore = bracket createStore deleteStore

-- | Find an exported module by name in the store.
findModule :: Store -> Text -> IO (Maybe ModuleInstance)
findModule (Store o) modName =
  withOwned o $ \p ->
    withWasmString modName $ \nameStr -> do
      mp <- c_StoreFindModule p nameStr
      if mp == nullPtr
        then pure Nothing
        else Just <$> borrowModule mp

-- | List all registered module names in the store.
listModules :: Store -> IO [Text]
listModules (Store o) =
  withOwned o $ \p -> do
    n <- c_StoreListModuleLength p
    if n == 0
      then pure []
      else allocaBytes (fromIntegral n * stringSize) $ \arr -> do
        _ <- c_StoreListModule p arr n
        forM [0 .. fromIntegral n - 1] $ \i -> do
          let ptr = arr `plusPtr` (i * stringSize)
          peekWasmString ptr

-- | Extract the raw pointer of a 'Store'.
unsafeStorePtr :: Store -> IO (Ptr StoreTag)
unsafeStorePtr (Store o) = withOwned o pure

-- | Create a borrowed 'Store' from a raw pointer (does not finalize).
borrowStore :: Ptr StoreTag -> IO Store
borrowStore p = Store <$> mkOwned (\_ -> pure ()) p -- no-op finalizer

appFunPtr :: FunPtr (Ptr a -> IO ()) -> Ptr a -> IO ()
appFunPtr = mkDeleter
foreign import ccall "dynamic" mkDeleter :: FunPtr (Ptr a -> IO ()) -> Ptr a -> IO ()