{-# LANGUAGE ScopedTypeVariables, TypeOperators #-}

module Data.Lexicographic.Generic.Internal where

import GHC.Generics

class GBounded ra where
  gminBound :: ra x
  gmaxBound :: ra x

instance GBounded U1 where
  gminBound :: U1 x
gminBound = U1 x
forall k (p :: k). U1 p
U1
  gmaxBound :: U1 x
gmaxBound = U1 x
forall k (p :: k). U1 p
U1

instance Bounded a => GBounded (K1 _m a) where
  gminBound :: K1 _m a x
gminBound = a -> K1 _m a x
forall k i c (p :: k). c -> K1 i c p
K1 a
forall a. Bounded a => a
minBound
  gmaxBound :: K1 _m a x
gmaxBound = a -> K1 _m a x
forall k i c (p :: k). c -> K1 i c p
K1 a
forall a. Bounded a => a
maxBound

instance GBounded ra => GBounded (M1 _d _m ra) where
  gminBound :: M1 _d _m ra x
gminBound = ra x -> M1 _d _m ra x
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gminBound
  gmaxBound :: M1 _d _m ra x
gmaxBound = ra x -> M1 _d _m ra x
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound

instance (GBounded ra, GBounded rb) => GBounded (ra :+: rb) where
  gminBound :: (:+:) ra rb x
gminBound = ra x -> (:+:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k). f p -> (:+:) f g p
L1 ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gminBound
  gmaxBound :: (:+:) ra rb x
gmaxBound = rb x -> (:+:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k). g p -> (:+:) f g p
R1 rb x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound

instance (GBounded ra, GBounded rb) => GBounded (ra :*: rb) where
  gminBound :: (:*:) ra rb x
gminBound = ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gminBound ra x -> rb x -> (:*:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: rb x
forall (ra :: * -> *) x. GBounded ra => ra x
gminBound
  gmaxBound :: (:*:) ra rb x
gmaxBound = ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound ra x -> rb x -> (:*:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: rb x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound

class GEnum ra where
  gfromEnum :: ra x -> Int
  gtoEnum :: Int -> ra x

instance GEnum U1 where
  gfromEnum :: U1 x -> Int
gfromEnum U1 x
U1 = Int
0
  gtoEnum :: Int -> U1 x
gtoEnum Int
0 = U1 x
forall k (p :: k). U1 p
U1
  gtoEnum Int
_ = [Char] -> U1 x
forall a. HasCallStack => [Char] -> a
error [Char]
"Import.GEnum.U1.gtoEnum: bad argument"

instance Enum a => GEnum (K1 _m a) where
  gfromEnum :: K1 _m a x -> Int
gfromEnum (K1 a
x) = a -> Int
forall a. Enum a => a -> Int
fromEnum a
x
  gtoEnum :: Int -> K1 _m a x
gtoEnum Int
n = a -> K1 _m a x
forall k i c (p :: k). c -> K1 i c p
K1 (Int -> a
forall a. Enum a => Int -> a
toEnum Int
n)

instance GEnum ra => GEnum (M1 _d _m ra) where
  gfromEnum :: M1 _d _m ra x -> Int
gfromEnum (M1 ra x
x) = ra x -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum ra x
x
  gtoEnum :: Int -> M1 _d _m ra x
gtoEnum Int
n = ra x -> M1 _d _m ra x
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 (Int -> ra x
forall (ra :: * -> *) x. GEnum ra => Int -> ra x
gtoEnum Int
n)

instance (GBounded ra, GEnum ra, GBounded rb, GEnum rb) => GEnum (ra :+: rb) where
  gfromEnum :: (:+:) ra rb x -> Int
gfromEnum (L1 ra x
x) = ra x -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum ra x
x
  gfromEnum (R1 rb x
y) = ra Any -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum (forall x. ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound :: ra x) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ rb x -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum rb x
y

  gtoEnum :: Int -> (:+:) ra rb x
gtoEnum Int
n
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= ra Any -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum (forall x. ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound :: ra x) = ra x -> (:+:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k). f p -> (:+:) f g p
L1 (Int -> ra x
forall (ra :: * -> *) x. GEnum ra => Int -> ra x
gtoEnum Int
n :: ra x)
    | Bool
otherwise = rb x -> (:+:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k). g p -> (:+:) f g p
R1 (Int -> rb x
forall (ra :: * -> *) x. GEnum ra => Int -> ra x
gtoEnum (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1 Int -> Int -> Int
forall a. Num a => a -> a -> a
- ra Any -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum (forall x. ra x
forall (ra :: * -> *) x. GBounded ra => ra x
gmaxBound :: ra x)))

instance (GBoundEnum ra, GBoundEnum rb) => GEnum (ra :*: rb) where
  gfromEnum :: (:*:) ra rb x -> Int
gfromEnum (ra x
x :*: rb x
y) = ra x -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum ra x
x Int -> Int -> Int
forall a. Num a => a -> a -> a
* ([rb Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [rb x])) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ rb x -> Int
forall (ra :: * -> *) x. GEnum ra => ra x -> Int
gfromEnum rb x
y
  gtoEnum :: Int -> (:*:) ra rb x
gtoEnum Int
n = case Int
n Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`divMod` [rb Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [rb x]) of
    (Int
n1,Int
n2) -> (Int -> ra x
forall (ra :: * -> *) x. GEnum ra => Int -> ra x
gtoEnum Int
n1 ra x -> rb x -> (:*:) ra rb x
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: Int -> rb x
forall (ra :: * -> *) x. GEnum ra => Int -> ra x
gtoEnum Int
n2)

class (GBounded ra, GEnum ra) => GBoundEnum ra where
  gcardinality :: p (ra x) -> Int

instance GBoundEnum U1 where
  gcardinality :: p (U1 x) -> Int
gcardinality p (U1 x)
_ = Int
1

instance (Bounded a, Enum a) => GBoundEnum (K1 _m a) where
  gcardinality :: p (K1 _m a x) -> Int
gcardinality p (K1 _m a x)
_ = [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length [a
forall a. Bounded a => a
minBound .. (a
forall a. Bounded a => a
maxBound :: a)]

instance GBoundEnum ra => GBoundEnum (M1 _d _m ra) where
  gcardinality :: p (M1 _d _m ra x) -> Int
gcardinality p (M1 _d _m ra x)
_ = [ra Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [ra x])

instance (GBoundEnum ra, GBoundEnum rb) => GBoundEnum (ra :+: rb) where
  gcardinality :: p ((:+:) ra rb x) -> Int
gcardinality p ((:+:) ra rb x)
_ = [ra Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [ra x]) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ [rb Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [rb x])

instance (GBoundEnum ra, GBoundEnum rb) => GBoundEnum (ra :*: rb) where
  gcardinality :: p ((:*:) ra rb x) -> Int
gcardinality p ((:*:) ra rb x)
_ = [ra Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [ra x]) Int -> Int -> Int
forall a. Num a => a -> a -> a
* [rb Any] -> Int
forall (ra :: * -> *) (p :: * -> *) x.
GBoundEnum ra =>
p (ra x) -> Int
gcardinality ([] :: [rb x])