packages feed

phino-0.0.0.22: src/Random.hs

-- SPDX-FileCopyrightText: Copyright (c) 2025 Objectionary.com
-- SPDX-License-Identifier: MIT

module Random (randomString) where

import Control.Monad (replicateM)
import Data.Char (intToDigit)
import Data.IORef (IORef, modifyIORef', newIORef, readIORef)
import Data.Set (Set)
import qualified Data.Set as Set
import GHC.IO (unsafePerformIO)
import System.Random (randomRIO)

strings :: IORef (Set String)
{-# NOINLINE strings #-}
strings = unsafePerformIO (newIORef Set.empty)

generate :: String -> IO String
generate [] = pure []
generate ('%' : ch : rest) = do
  rep <- case ch of
    'x' -> replicateM 8 $ do
      v <- randomRIO (0, 15)
      pure (intToDigit v)
    'd' -> show <$> randomRIO (0 :: Int, 9999)
    _ -> pure ['%', ch]
  next <- generate rest
  pure (rep ++ next)
generate (ch : rest) = do
  rest' <- generate rest
  pure (ch : rest')

regenerate :: String -> Set String -> IO String
regenerate pat set = do
  next <- generate pat
  if next `Set.member` set
    then regenerate pat set
    else do
      modifyIORef' strings (Set.insert next)
      pure next

randomString :: String -> IO String
randomString pat = do
  set <- readIORef strings
  regenerate pat set