packages feed

wasmedge-hs-0.17.1.0: examples/Stress/StoreReflection.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

{- |
Module      : Stress.StoreReflection
Description : Comprehensive Store and ModuleInstance introspection & reflection suite
Copyright   : (c) 2026 Tushar Adhatrao
License     : MIT
Stability   : experimental

Exercises:
  * 'listModules' / 'findModule' on 'Store'
  * 'getModuleName' on 'ModuleInstance'
  * 'listFunctions' / 'findFunction'
  * 'listMemories' / 'findMemory'
  * 'listTables' / 'findTable'
  * 'listGlobals' / 'findGlobal'
  * 'listTags' / 'findTag'
-}
module Stress.StoreReflection
  ( runStoreReflectionSuite
  , StoreReflectionMetrics (..)
  ) where

import Control.Monad (unless)
import Data.Int (Int32)
import Data.Maybe (isJust, isNothing)
import Data.Text (Text)
import Data.Text qualified as T
import System.Clock (Clock (Monotonic), diffTimeSpec, getTime, toNanoSecs)
import Text.Printf (printf)

import WasmEdge.Executor (createExecutor, deleteExecutor, registerImportModule)
import WasmEdge.Global (createGlobal, createGlobalType, deleteGlobalType)
import WasmEdge.Memory (createMemory, createMemoryType, deleteMemoryType)
import WasmEdge.Module
  ( buildHostModule
  , builderAddGlobal
  , builderAddHostFunc
  , builderAddMemory
  , builderAddTable
  , findFunction
  , findGlobal
  , findMemory
  , findTable
  , findTag
  , getModuleName
  , listFunctions
  , listGlobals
  , listMemories
  , listTables
  , listTags
  )
import WasmEdge.Store (createStore, deleteStore, findModule, listModules)
import WasmEdge.Table (createTable, createTableType, deleteTableType)
import WasmEdge.Types (Limit (..), Mutability (..), ValType (..), WasmVal (..))

data StoreReflectionMetrics = StoreReflectionMetrics
  { srmModulesCount :: !Int
  , srmFunctionsReflected :: ![Text]
  , srmMemoriesReflected :: ![Text]
  , srmTablesReflected :: ![Text]
  , srmGlobalsReflected :: ![Text]
  , srmTagsReflected :: ![Text]
  , srmDurationSec :: !Double
  }
  deriving stock (Show)

runStoreReflectionSuite :: IO StoreReflectionMetrics
runStoreReflectionSuite = do
  putStrLn "============================================================"
  putStrLn "  STRESS TEST: Store & Module Instance Introspection"
  putStrLn "============================================================"

  t0 <- getTime Monotonic

  -- 1. Create a Store and Executor
  putStrLn "[1/5] Creating runtime Store & Executor..."
  store <- createStore
  executor <- createExecutor Nothing Nothing

  -- 2. Build a rich host module exporting function, memory, table, and global
  putStrLn "[2/5] Constructing multi-export HostModule..."
  memType <- createMemoryType (Limit 2 (Just 10) False)
  memInst <- createMemory memType
  deleteMemoryType memType

  tabType <- createTableType FuncRefT (Limit 5 (Just 20) False)
  tabInst <- createTable tabType
  deleteTableType tabType

  globType <- createGlobalType I32 Var
  globInst <- createGlobal globType (WasmI32 1001)
  deleteGlobalType globType

  hostMod <- buildHostModule "reflection_catalog_mod" $ \builder -> do
    builderAddHostFunc builder "catalog_version" (pure 42 :: IO Int32)
    builderAddHostFunc builder "catalog_ping" (\(x :: Int32) -> pure (x + 1) :: IO Int32)
    builderAddMemory builder "catalog_mem" memInst
    builderAddTable builder "catalog_tab" tabInst
    builderAddGlobal builder "catalog_counter" globInst

  -- 3. Register module into store
  putStrLn "[3/5] Registering HostModule into Store..."
  resReg <- registerImportModule executor store hostMod
  case resReg of
    Left err -> fail $ "Failed to register host module into store: " ++ show err
    Right () -> putStrLn "      Registered successfully."

  -- 4. Store reflection: listModules and findModule
  putStrLn "[4/5] Reflecting on registered modules in Store..."
  allMods <- listModules store
  printf "      Registered modules in store: %s\n" (show allMods)
  unless ("reflection_catalog_mod" `elem` allMods) $
    fail "Module 'reflection_catalog_mod' not found in store listModules!"

  mFoundMod <- findModule store "reflection_catalog_mod"
  foundMod <- case mFoundMod of
    Nothing -> fail "findModule failed to locate 'reflection_catalog_mod'!"
    Just m -> pure m

  modName <- getModuleName foundMod
  printf "      Module name confirmed: %s\n" (T.unpack modName)

  -- 5. Module reflection: list and find each exported component
  putStrLn "[5/5] Reflecting on exports: functions, memories, tables, globals, tags..."
  funcs <- listFunctions foundMod
  printf "      Exported functions: %s\n" (show funcs)
  unless ("catalog_version" `elem` funcs && "catalog_ping" `elem` funcs) $
    fail "Exported functions reflection incomplete!"
  mFn <- findFunction foundMod "catalog_version"
  unless (isJust mFn) $ fail "findFunction 'catalog_version' failed!"

  mems <- listMemories foundMod
  printf "      Exported memories: %s\n" (show mems)
  unless ("catalog_mem" `elem` mems) $
    fail "Exported memories reflection incomplete!"
  mMem <- findMemory foundMod "catalog_mem"
  unless (isJust mMem) $ fail "findMemory 'catalog_mem' failed!"

  tabs <- listTables foundMod
  printf "      Exported tables: %s\n" (show tabs)
  unless ("catalog_tab" `elem` tabs) $
    fail "Exported tables reflection incomplete!"
  mTab <- findTable foundMod "catalog_tab"
  unless (isJust mTab) $ fail "findTable 'catalog_tab' failed!"

  globs <- listGlobals foundMod
  printf "      Exported globals: %s\n" (show globs)
  unless ("catalog_counter" `elem` globs) $
    fail "Exported globals reflection incomplete!"
  mGlob <- findGlobal foundMod "catalog_counter"
  unless (isJust mGlob) $ fail "findGlobal 'catalog_counter' failed!"

  tags <- listTags foundMod
  printf "      Exported tags: %s\n" (show tags)
  mTag <- findTag foundMod "dummy_tag"
  unless (isNothing mTag) $ fail "findTag on dummy should be Nothing!"

  deleteStore store
  deleteExecutor executor

  t1 <- getTime Monotonic
  let dur = fromIntegral (toNanoSecs (diffTimeSpec t1 t0)) / 1e9 :: Double
  printf ">>> Store Reflection Suite completed in %.3f s\n\n" dur

  pure
    StoreReflectionMetrics
      { srmModulesCount = length allMods
      , srmFunctionsReflected = funcs
      , srmMemoriesReflected = mems
      , srmTablesReflected = tabs
      , srmGlobalsReflected = globs
      , srmTagsReflected = tags
      , srmDurationSec = dur
      }