{-# 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 :: forall a. (Bounded a, Enum a) => NonEmpty a -> Quid
nonEmptyListToQuid NonEmpty a
xs = Natural -> Quid
Quid forall a b. (a -> b) -> a -> b
$
    forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' forall {a}. Enum a => Natural -> a -> Natural
f Natural
0 NonEmpty a
xs forall a. Num a => a -> a -> a
- Natural
1
  where
    f :: Natural -> a -> Natural
f !Natural
acc !a
x = Natural
acc forall a. Num a => a -> a -> a
* Natural
base forall a. Num a => a -> a -> a
+ Natural
1 forall a. Num a => a -> a -> a
+ forall a b. (Integral a, Num b) => a -> b
fromIntegral (forall a. Enum a => a -> Int
fromEnum a
x)
    base :: Natural
base = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @Natural forall a b. (a -> b) -> a -> b
$ forall a. (Bounded a, Enum a) => Proxy a -> Int
boundedEnumCardinality forall a b. (a -> b) -> a -> b
$ forall {k} (t :: k). Proxy t
Proxy @a

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

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