{-|
Copyright   : (C) 2021-2022, QBayLogic B.V.
License     : BSD2 (see the file LICENSE)
Maintainer  : QBayLogic B.V. <devops@qbaylogic.com>

Random generation of Signed numbers.
-}

{-# OPTIONS_GHC -fplugin=GHC.TypeLits.KnownNat.Solver #-}

{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}

module Clash.Hedgehog.Sized.Signed
  ( genSigned
  , SomeSigned(..)
  , genSomeSigned
  ) where

#if !MIN_VERSION_base(4,16,0)
import GHC.Natural (Natural)
#endif
import GHC.TypeNats
#if MIN_VERSION_base(4,18,0)
  hiding (SNat)
#endif
import Hedgehog (MonadGen, Range)
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range

import Clash.Promoted.Nat
import Clash.Sized.Internal.Signed

genSigned :: (MonadGen m, KnownNat n) => Range (Signed n) -> m (Signed n)
genSigned :: Range (Signed n) -> m (Signed n)
genSigned Range (Signed n)
range =
  [(Int, m (Signed n))] -> m (Signed n)
forall (m :: Type -> Type) a. MonadGen m => [(Int, m a)] -> m a
Gen.frequency
    [ (Int
60, Range (Signed n) -> m (Signed n)
forall (m :: Type -> Type) a.
(MonadGen m, Integral a) =>
Range a -> m a
Gen.integral Range (Signed n)
range)
    , (Int
20, Signed n -> m (Signed n)
forall (m :: Type -> Type) a. MonadGen m => a -> m a
Gen.constant (Size -> Range (Signed n) -> Signed n
forall a. Ord a => Size -> Range a -> a
Range.lowerBound Size
99 Range (Signed n)
range))
    , (Int
20, Signed n -> m (Signed n)
forall (m :: Type -> Type) a. MonadGen m => a -> m a
Gen.constant (Size -> Range (Signed n) -> Signed n
forall a. Ord a => Size -> Range a -> a
Range.upperBound Size
99 Range (Signed n)
range))
    ]

data SomeSigned atLeast where
  SomeSigned :: SNat n -> Signed (atLeast + n) -> SomeSigned atLeast

instance KnownNat atLeast => Show (SomeSigned atLeast) where
  show :: SomeSigned atLeast -> String
show (SomeSigned SNat n
SNat Signed (atLeast + n)
x) = Signed (atLeast + n) -> String
forall a. Show a => a -> String
show Signed (atLeast + n)
x

genSomeSigned
  :: (MonadGen m, KnownNat atLeast)
  => Range Natural
  -> m (SomeSigned atLeast)
genSomeSigned :: Range Natural -> m (SomeSigned atLeast)
genSomeSigned Range Natural
rangeSigned = do
  Natural
numExtra <- Range Natural -> m Natural
forall (m :: Type -> Type) a.
(MonadGen m, Integral a) =>
Range a -> m a
Gen.integral Range Natural
rangeSigned

  case Natural -> SomeNat
someNatVal Natural
numExtra of
    SomeNat Proxy n
proxy -> SNat n -> Signed (atLeast + n) -> SomeSigned atLeast
forall (n :: Nat) (atLeast :: Nat).
SNat n -> Signed (atLeast + n) -> SomeSigned atLeast
SomeSigned (Proxy n -> SNat n
forall (n :: Nat) (proxy :: Nat -> Type).
KnownNat n =>
proxy n -> SNat n
snatProxy Proxy n
proxy) (Signed (atLeast + n) -> SomeSigned atLeast)
-> m (Signed (atLeast + n)) -> m (SomeSigned atLeast)
forall (f :: Type -> Type) a b. Functor f => (a -> b) -> f a -> f b
<$> Range (Signed (atLeast + n)) -> m (Signed (atLeast + n))
forall (m :: Type -> Type) (n :: Nat).
(MonadGen m, KnownNat n) =>
Range (Signed n) -> m (Signed n)
genSigned Range (Signed (atLeast + n))
forall a. (Bounded a, Integral a) => Range a
Range.linearBounded