packages feed

quickcheck-quid-0.0.1.1: src/internal/Internal/Test/QuickCheck/Quid/Representations.hs

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}

module Internal.Test.QuickCheck.Quid.Representations
    where

import Data.List.NonEmpty
    ( NonEmpty )
import Data.Proxy
    ( Proxy (..) )
import Internal.Test.QuickCheck.Quid
    ( Quid (..) )
import Numeric.Natural
    ( Natural )

import qualified Data.Foldable as F
import qualified Data.List.NonEmpty as NE

nonEmptyListToQuid :: forall a. (Bounded a, Enum a) => NonEmpty a -> Quid
nonEmptyListToQuid xs = Quid $
    F.foldl' f 0 xs - 1
  where
    f !acc !x = acc * base + 1 + fromIntegral (fromEnum x)
    base = fromIntegral @Int @Natural $ boundedEnumCardinality $ Proxy @a

nonEmptyListFromQuid :: forall a. (Bounded a, Enum a) => Quid -> NonEmpty a
nonEmptyListFromQuid (Quid q) =
    NE.fromList $ go [] q
  where
    go :: [a] -> Natural -> [a]
    go !acc !n
        | n < base =
            toEnum (fromIntegral n) : acc
        | otherwise =
            go (toEnum (fromIntegral (n `mod` base)) : acc) (n `div` base - 1)
    base = fromIntegral @Int @Natural $ boundedEnumCardinality $ Proxy @a

boundedEnumCardinality :: forall a. (Bounded a, Enum a) => Proxy a -> Int
boundedEnumCardinality _ = fromEnum (maxBound @a) - fromEnum (minBound @a) + 1