{-# LANGUAGE TypeApplications #-}

-- | Seed used for the ThreadNet tests
module Test.ThreadNet.Util.Seed (
    Seed (..)
  , combineWith
  , runGen
  ) where

import           Data.Bits (xor)
import           Data.Coerce (coerce)
import           Test.QuickCheck
import           Test.QuickCheck.Gen
import           Test.QuickCheck.Random (mkQCGen)

newtype Seed = Seed Int
  deriving (Seed -> Seed -> Bool
(Seed -> Seed -> Bool) -> (Seed -> Seed -> Bool) -> Eq Seed
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Seed -> Seed -> Bool
== :: Seed -> Seed -> Bool
$c/= :: Seed -> Seed -> Bool
/= :: Seed -> Seed -> Bool
Eq, Int -> Seed -> ShowS
[Seed] -> ShowS
Seed -> String
(Int -> Seed -> ShowS)
-> (Seed -> String) -> ([Seed] -> ShowS) -> Show Seed
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Seed -> ShowS
showsPrec :: Int -> Seed -> ShowS
$cshow :: Seed -> String
show :: Seed -> String
$cshowList :: [Seed] -> ShowS
showList :: [Seed] -> ShowS
Show)

instance Semigroup Seed where
  <> :: Seed -> Seed -> Seed
(<>) = (Int -> Int -> Int) -> Seed -> Seed -> Seed
forall a b. Coercible a b => a -> b
coerce (forall a. Bits a => a -> a -> a
xor @Int)

combineWith :: Integral a => Seed -> a -> Seed
combineWith :: forall a. Integral a => Seed -> a -> Seed
combineWith Seed
seed a
x = Seed
seed Seed -> Seed -> Seed
forall a. Semigroup a => a -> a -> a
<> Int -> Seed
Seed (a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
x)

runGen :: Seed -> Gen a -> a
runGen :: forall a. Seed -> Gen a -> a
runGen (Seed Int
seed) Gen a
g =
    Gen a -> QCGen -> Int -> a
forall a. Gen a -> QCGen -> Int -> a
unGen Gen a
g QCGen
qcSeed Int
qcSize
  where
    -- The traditional initial QC size
    qcSize :: Int
qcSize = Int
30 :: Int
    qcSeed :: QCGen
qcSeed = Int -> QCGen
mkQCGen Int
seed

instance Arbitrary Seed where
  arbitrary :: Gen Seed
arbitrary = Int -> Seed
Seed (Int -> Seed) -> Gen Int -> Gen Seed
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Int, Int) -> Gen Int
forall a. Random a => (a, a) -> Gen a
choose (Int
forall a. Bounded a => a
minBound, Int
forall a. Bounded a => a
maxBound)