-- | Simple (i.e., non-compound) generators
module Test.Falsify.Internal.Generator.Simple (
    bool
  , inRange
  , int
  ) where

import Prelude hiding (properFraction)

import Data.Bits
import Data.Word

import Test.Falsify.Internal.Generator
import Test.Falsify.Internal.Generator.Precision
import Test.Falsify.Internal.Range
import Test.Falsify.SampleTree (Sample(..))

import qualified Test.Falsify.Range      as Range
import qualified Test.Falsify.SampleTree as SampleTree

{-------------------------------------------------------------------------------
  Simple generators
-------------------------------------------------------------------------------}

-- | Generate random bool, shrink towards the given value
--
-- Chooses with equal probability between 'True' and 'False'.
bool :: Bool -> Gen Bool
bool :: Bool -> Gen Bool
bool Bool
target = Word64 -> Bool
aux (Word64 -> Bool) -> (Sample -> Word64) -> Sample -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Sample -> Word64
SampleTree.sampleValue (Sample -> Bool) -> Gen Sample -> Gen Bool
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (Sample -> [Word64]) -> Gen Sample
primWith Sample -> [Word64]
shrinker
  where
    aux :: Word64 -> Bool
    aux :: Word64 -> Bool
aux Word64
x | Word64 -> Bool
forall a. FiniteBits a => a -> Bool
msbSet Word64
x  = Bool -> Bool
not Bool
target
          | Bool
otherwise = Bool
target

    msbSet :: forall a. FiniteBits a => a -> Bool
    msbSet :: forall a. FiniteBits a => a -> Bool
msbSet a
x = a -> Int -> Bool
forall a. Bits a => a -> Int -> Bool
testBit a
x (a -> Int
forall b. FiniteBits b => b -> Int
finiteBitSize (a
forall a. HasCallStack => a
undefined :: a) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1)

    shrinker :: Sample -> [Word64]
    shrinker :: Sample -> [Word64]
shrinker (Shrunk Word64
0) = []
    shrinker Sample
_          = [Word64
0]

{-------------------------------------------------------------------------------
  Integral ranges
-------------------------------------------------------------------------------}

-- | Generate value in the specified range
inRange :: Range a -> Gen a
inRange :: forall a. Range a -> Gen a
inRange Range a
r = (Precision -> Gen WordN) -> Range a -> Gen a
forall (f :: * -> *) a.
Applicative f =>
(Precision -> f WordN) -> Range a -> f a
Range.eval Precision -> Gen WordN
wordN Range a
r

-- | Type-specialization of 'inRange'
int :: Range Int -> Gen Int
int :: Range Int -> Gen Int
int = Range Int -> Gen Int
forall a. Range a -> Gen a
inRange