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 :: IORef (Set String)
strings = IO (IORef (Set String)) -> IORef (Set String)
forall a. IO a -> a
unsafePerformIO (Set String -> IO (IORef (Set String))
forall a. a -> IO (IORef a)
newIORef Set String
forall a. Set a
Set.empty)
generate :: String -> IO String
generate :: String -> IO String
generate [] = String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure []
generate (Char
'%' : Char
ch : String
rest) = do
String
rep <- case Char
ch of
Char
'x' -> Int -> IO Char -> IO String
forall (m :: * -> *) a. Applicative m => Int -> m a -> m [a]
replicateM Int
8 (IO Char -> IO String) -> IO Char -> IO String
forall a b. (a -> b) -> a -> b
$ do
Int
v <- (Int, Int) -> IO Int
forall a (m :: * -> *). (Random a, MonadIO m) => (a, a) -> m a
randomRIO (Int
0, Int
15)
Char -> IO Char
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Int -> Char
intToDigit Int
v)
Char
'd' -> Int -> String
forall a. Show a => a -> String
show (Int -> String) -> IO Int -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int, Int) -> IO Int
forall a (m :: * -> *). (Random a, MonadIO m) => (a, a) -> m a
randomRIO (Int
0 :: Int, Int
9999)
Char
_ -> String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure [Char
'%', Char
ch]
String
next <- String -> IO String
generate String
rest
String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (String
rep String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
next)
generate (Char
ch : String
rest) = do
String
rest' <- String -> IO String
generate String
rest
String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Char
ch Char -> String -> String
forall a. a -> [a] -> [a]
: String
rest')
regenerate :: String -> Set String -> IO String
regenerate :: String -> Set String -> IO String
regenerate String
pat Set String
set = do
String
next <- String -> IO String
generate String
pat
if String
next String -> Set String -> Bool
forall a. Ord a => a -> Set a -> Bool
`Set.member` Set String
set
then String -> Set String -> IO String
regenerate String
pat Set String
set
else do
IORef (Set String) -> (Set String -> Set String) -> IO ()
forall a. IORef a -> (a -> a) -> IO ()
modifyIORef' IORef (Set String)
strings (String -> Set String -> Set String
forall a. Ord a => a -> Set a -> Set a
Set.insert String
next)
String -> IO String
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure String
next
randomString :: String -> IO String
randomString :: String -> IO String
randomString String
pat = do
Set String
set <- IORef (Set String) -> IO (Set String)
forall a. IORef a -> IO a
readIORef IORef (Set String)
strings
String -> Set String -> IO String
regenerate String
pat Set String
set