packages feed

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

{-# LANGUAGE OverloadedStrings #-}

{- |
Module      : Stress.TagException
Description : Stress testing WebAssembly Tag types, instances, and exception proposal support
Copyright   : (c) 2026 Tushar Adhatrao
License     : MIT
Stability   : experimental

Exercises:
  * 'TagType' / 'getTagTypeFunctionType'
  * 'TagInstance' / 'getTagInstanceType'
  * 'borrowTagType' / 'borrowTagInstance'
  * 'unsafeTagTypePtr' / 'unsafeTagInstancePtr'
  * 'listTags' / 'findTag' on 'ModuleInstance'
-}
module Stress.TagException
  ( runTagExceptionSuite
  , TagMetrics (..)
  ) where

import Control.Monad (unless)
import Foreign.Ptr (nullPtr)
import System.Clock (Clock (Monotonic), diffTimeSpec, getTime, toNanoSecs)
import Text.Printf (printf)

import WasmEdge.Configure (addProposal, createConfigure, hasProposal)
import WasmEdge.Module (createHostModule, deleteModuleInstance, findTag, listTags)
import WasmEdge.Tag
  ( borrowTagInstance
  , borrowTagType
  , unsafeTagInstancePtr
  , unsafeTagTypePtr
  )
import WasmEdge.Types (Proposal (..))

data TagMetrics = TagMetrics
  { tmExceptionsProposalEnabled :: !Bool
  , tmTagListingVerified :: !Bool
  , tmTagQuerySafeGraceful :: !Bool
  , tmTagPointersVerified :: !Bool
  , tagmDurationSec :: !Double
  }
  deriving stock (Show)

runTagExceptionSuite :: IO TagMetrics
runTagExceptionSuite = do
  putStrLn "============================================================"
  putStrLn "  STRESS TEST: Tag Instances & Exception Proposal Subsystem"
  putStrLn "============================================================"

  t0 <- getTime Monotonic

  -- 1. Configure Exception Handling Proposal
  putStrLn "[1/4] Enabling Proposals_Exceptions in WasmEdge Configuration..."
  conf <- createConfigure
  addProposal conf ExceptionHandling
  hasExceptions <- hasProposal conf ExceptionHandling
  printf "      Exceptions proposal active: %s\n" (show hasExceptions)
  unless hasExceptions $ fail "Exceptions proposal should be active!"

  -- 2. Module Tag Inspection
  putStrLn "[2/4] Inspecting Tag exports on host module instances..."
  modInst <- createHostModule "exception_test_mod"
  tags <- listTags modInst
  printf "      Initial tags on fresh host module: %s\n" (show tags)
  unless (null tags) $ fail "Fresh host module should have 0 exported tags!"

  -- 3. Graceful Nothing handling for nonexistent tags
  putStrLn "[3/4] Querying non-existent tag via findTag..."
  mTag <- findTag modInst "nonexistent_tag"
  case mTag of
    Nothing -> putStrLn "      findTag returned Nothing gracefully (VERIFIED)"
    Just _ -> fail "findTag should have returned Nothing for nonexistent tag!"

  -- 4. Tag type and instance pointer conversions
  putStrLn "[4/4] Verifying TagInstance and TagType internal conversion helpers..."
  -- Test borrowTagInstance & unsafeTagInstancePtr roundtrip with null pointer representation
  tagInst <- borrowTagInstance nullPtr
  let pInst = unsafeTagInstancePtr tagInst
  unless (pInst == nullPtr) $ fail "TagInstance pointer roundtrip mismatch!"

  tagTy <- borrowTagType nullPtr
  let pTy = unsafeTagTypePtr tagTy
  unless (pTy == nullPtr) $ fail "TagType pointer roundtrip mismatch!"

  deleteModuleInstance modInst

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

  pure
    TagMetrics
      { tmExceptionsProposalEnabled = hasExceptions
      , tmTagListingVerified = null tags
      , tmTagQuerySafeGraceful = True
      , tmTagPointersVerified = True
      , tagmDurationSec = dur
      }