{-# 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 (Natural -> Quid) -> Natural -> Quid
forall a b. (a -> b) -> a -> b
$
    (Natural -> a -> Natural) -> Natural -> NonEmpty a -> Natural
forall b a. (b -> a -> b) -> b -> NonEmpty a -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
F.foldl' Natural -> a -> Natural
forall {a}. Enum a => Natural -> a -> Natural
f Natural
0 NonEmpty a
xs Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
1
  where
    f :: Natural -> a -> Natural
f !Natural
acc !a
x = Natural
acc Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
* Natural
base Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Natural
1 Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
+ Int -> Natural
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a -> Int
forall a. Enum a => a -> Int
fromEnum a
x)
    base :: Natural
base = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @Natural (Int -> Natural) -> Int -> Natural
forall a b. (a -> b) -> a -> b
$ Proxy a -> Int
forall a. (Bounded a, Enum a) => Proxy a -> Int
boundedEnumCardinality (Proxy a -> Int) -> Proxy a -> Int
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
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) =
    [a] -> NonEmpty a
forall a. HasCallStack => [a] -> NonEmpty a
NE.fromList ([a] -> NonEmpty a) -> [a] -> NonEmpty a
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 Natural -> Natural -> Bool
forall a. Ord a => a -> a -> Bool
< Natural
base =
            Int -> a
forall a. Enum a => Int -> a
toEnum (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Natural
n) a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
acc
        | Bool
otherwise =
            [a] -> Natural -> [a]
go (Int -> a
forall a. Enum a => Int -> a
toEnum (Natural -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Natural
n Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`mod` Natural
base)) a -> [a] -> [a]
forall a. a -> [a] -> [a]
: [a]
acc) (Natural
n Natural -> Natural -> Natural
forall a. Integral a => a -> a -> a
`div` Natural
base Natural -> Natural -> Natural
forall a. Num a => a -> a -> a
- Natural
1)
    base :: Natural
base = forall a b. (Integral a, Num b) => a -> b
fromIntegral @Int @Natural (Int -> Natural) -> Int -> Natural
forall a b. (a -> b) -> a -> b
$ Proxy a -> Int
forall a. (Bounded a, Enum a) => Proxy a -> Int
boundedEnumCardinality (Proxy a -> Int) -> Proxy a -> Int
forall a b. (a -> b) -> a -> b
$ forall t. Proxy t
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
_ = a -> Int
forall a. Enum a => a -> Int
fromEnum (forall a. Bounded a => a
maxBound @a) Int -> Int -> Int
forall a. Num a => a -> a -> a
- a -> Int
forall a. Enum a => a -> Int
fromEnum (forall a. Bounded a => a
minBound @a) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1