{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

-- | Generic deriving for 'Enum', 'Bounded' and 'Ix'.
--
-- === Warning
--
-- This is an internal module: it is not subject to any versioning policy,
-- breaking changes can happen at any time.
--
-- If something here seems useful, please report it or create a pull request to
-- export it from an external module.

module Generic.Data.Internal.Enum where

import GHC.Generics
import Data.Ix

-- | Generic 'toEnum' generated with the 'StandardEnum' option.
--
-- @
-- instance 'Enum' MyType where
--   'toEnum' = 'gtoEnum'
--   'fromEnum' = 'gfromEnum'
--   'enumFrom' = 'genumFrom'
--   'enumFromThen' = 'genumFromThen'
--   'enumFromTo' = 'genumFromTo'
--   'enumFromThenTo' = 'genumFromThenTo'
-- @
gtoEnum :: (Generic a, GEnum StandardEnum (Rep a)) => Int -> a
gtoEnum :: Int -> a
gtoEnum = String -> Int -> a
forall opts a.
(Generic a, GEnum opts (Rep a)) =>
String -> Int -> a
gtoEnum' @StandardEnum String
"gtoEnum"

-- | Generic 'fromEnum' generated with the 'StandardEnum' option.
--
-- See also 'gtoEnum'.
gfromEnum :: (Generic a, GEnum StandardEnum (Rep a)) => a -> Int
gfromEnum :: a -> Int
gfromEnum = forall a. (Generic a, GEnum StandardEnum (Rep a)) => a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum' @StandardEnum

-- | Generic 'enumFrom' generated with the 'StandardEnum' option.
--
-- See also 'gtoEnum'.
genumFrom :: (Generic a, GEnum StandardEnum (Rep a)) => a -> [a]
genumFrom :: a -> [a]
genumFrom = forall a. (Generic a, GEnum StandardEnum (Rep a)) => a -> [a]
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> [a]
genumFrom' @StandardEnum

-- | Generic 'enumFromThen' generated with the 'StandardEnum' option.
--
-- See also 'gtoEnum'.
genumFromThen :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
genumFromThen :: a -> a -> [a]
genumFromThen = forall a. (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
genumFromThen' @StandardEnum

-- | Generic 'enumFromTo' generated with the 'StandardEnum' option.
--
-- See also 'gtoEnum'.
genumFromTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
genumFromTo :: a -> a -> [a]
genumFromTo = forall a. (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> [a]
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
genumFromTo' @StandardEnum

-- | Generic 'enumFromThenTo' generated with the 'StandardEnum' option.
--
-- See also 'gtoEnum'.
genumFromThenTo :: (Generic a, GEnum StandardEnum (Rep a)) => a -> a -> a -> [a]
genumFromThenTo :: a -> a -> a -> [a]
genumFromThenTo = forall a.
(Generic a, GEnum StandardEnum (Rep a)) =>
a -> a -> a -> [a]
forall opts a.
(Generic a, GEnum opts (Rep a)) =>
a -> a -> a -> [a]
genumFromThenTo' @StandardEnum


-- | Generic 'toEnum' generated with the 'FiniteEnum' option.
--
-- @
-- instance 'Enum' MyType where
--   'toEnum' = 'gtoFiniteEnum'
--   'fromEnum' = 'gfromFiniteEnum'
--   'enumFrom' = 'gfiniteEnumFrom'
--   'enumFromThen' = 'gfiniteEnumFromThen'
--   'enumFromTo' = 'gfiniteEnumFromTo'
--   'enumFromThenTo' = 'gfiniteEnumFromThenTo'
-- @
gtoFiniteEnum :: (Generic a, GEnum FiniteEnum (Rep a)) => Int -> a
gtoFiniteEnum :: Int -> a
gtoFiniteEnum = String -> Int -> a
forall opts a.
(Generic a, GEnum opts (Rep a)) =>
String -> Int -> a
gtoEnum' @FiniteEnum String
"gtoFiniteEnum"

-- | Generic 'fromEnum' generated with the 'FiniteEnum' option.
--
-- See also 'gtoFiniteEnum'.
gfromFiniteEnum :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> Int
gfromFiniteEnum :: a -> Int
gfromFiniteEnum = forall a. (Generic a, GEnum FiniteEnum (Rep a)) => a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum' @FiniteEnum

-- | Generic 'enumFrom' generated with the 'FiniteEnum' option.
--
-- See also 'gtoFiniteEnum'.
gfiniteEnumFrom :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> [a]
gfiniteEnumFrom :: a -> [a]
gfiniteEnumFrom = forall a. (Generic a, GEnum FiniteEnum (Rep a)) => a -> [a]
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> [a]
genumFrom' @FiniteEnum

-- | Generic 'enumFromThen' generated with the 'FiniteEnum' option.
--
-- See also 'gtoFiniteEnum'.
gfiniteEnumFromThen :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
gfiniteEnumFromThen :: a -> a -> [a]
gfiniteEnumFromThen = forall a. (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
genumFromThen' @FiniteEnum

-- | Generic 'enumFromTo' generated with the 'FiniteEnum' option.
--
-- See also 'gtoFiniteEnum'.
gfiniteEnumFromTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
gfiniteEnumFromTo :: a -> a -> [a]
gfiniteEnumFromTo = forall a. (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> [a]
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
genumFromTo' @FiniteEnum

-- | Generic 'enumFromThenTo' generated with the 'FiniteEnum' option.
--
-- See also 'gtoFiniteEnum'.
gfiniteEnumFromThenTo :: (Generic a, GEnum FiniteEnum (Rep a)) => a -> a -> a -> [a]
gfiniteEnumFromThenTo :: a -> a -> a -> [a]
gfiniteEnumFromThenTo = forall a.
(Generic a, GEnum FiniteEnum (Rep a)) =>
a -> a -> a -> [a]
forall opts a.
(Generic a, GEnum opts (Rep a)) =>
a -> a -> a -> [a]
genumFromThenTo' @FiniteEnum

-- | Unsafe generic 'toEnum'. Does not check whether the argument is within
-- valid bounds. Use 'gtoEnum' or 'gtoFiniteEnum' instead.
gtoEnumRaw' :: forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
gtoEnumRaw' :: Int -> a
gtoEnumRaw' = Rep a Any -> a
forall a x. Generic a => Rep a x -> a
to (Rep a Any -> a) -> (Int -> Rep a Any) -> Int -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
forall (f :: * -> *) p. GEnum opts f => Int -> f p
gToEnum @opts

-- | Generic 'toEnum'. Use 'gfromEnum' or 'gfromFiniteEnum' instead.
gtoEnum' :: forall opts a. (Generic a, GEnum opts (Rep a)) => String -> Int -> a
gtoEnum' :: String -> Int -> a
gtoEnum' String
name Int
n
  | Int
0 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
n Bool -> Bool -> Bool
&& Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
card = Int -> a
forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
gtoEnumRaw' @opts Int
n
  | Bool
otherwise = String -> a
forall a. HasCallStack => String -> a
error (String -> a) -> String -> a
forall a b. (a -> b) -> a -> b
$
      String
name String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
": out of bounds, index " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
n String -> String -> String
forall a. [a] -> [a] -> [a]
++ String
", cardinality " String -> String -> String
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
show Int
card
  where
    card :: Int
card = GEnum opts (Rep a) => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @(Rep a)

-- | Generic 'fromEnum'. Use 'gfromEnum' or 'gfromFiniteEnum' instead.
gfromEnum' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum' :: a -> Int
gfromEnum' = forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
forall (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @opts (Rep a Any -> Int) -> (a -> Rep a Any) -> a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from

-- | > genumMin == gfromEnum gminBound
genumMin :: Int
genumMin :: Int
genumMin = Int
0

-- | > genumMax == gfromEnum gmaxBound
genumMax :: forall opts a. (Generic a, GEnum opts (Rep a)) => Int
genumMax :: Int
genumMax = GEnum opts (Rep a) => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @(Rep a) Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
1

-- | Generic 'enumFrom'. Use 'genumFrom' or 'gfiniteEnumFrom' instead.
genumFrom' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> [a]
genumFrom' :: a -> [a]
genumFrom' a
x = (Int -> a) -> [Int] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map Int -> a
toE [ Int
i_x .. (Generic a, GEnum opts (Rep a)) => Int
forall opts a. (Generic a, GEnum opts (Rep a)) => Int
genumMax @opts @a ]
  where
    toE :: Int -> a
toE = forall a. (Generic a, GEnum opts (Rep a)) => Int -> a
forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
gtoEnumRaw' @opts
    i_x :: Int
i_x = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
x

-- | Generic 'enumFromThen'. Use 'genumFromThen' or 'gfiniteEnumFromThen' instead.
genumFromThen' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
genumFromThen' :: a -> a -> [a]
genumFromThen' a
x1 a
x2 = (Int -> a) -> [Int] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map Int -> a
toE [ Int
i_x1, Int
i_x2 .. Int
bound ]
  where
    toE :: Int -> a
toE  = forall a. (Generic a, GEnum opts (Rep a)) => Int -> a
forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
gtoEnumRaw' @opts
    i_x1 :: Int
i_x1 = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
x1
    i_x2 :: Int
i_x2 = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
x2
    bound :: Int
bound | Int
i_x1 Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
i_x2 = Int
genumMin
          | Bool
otherwise    = (Generic a, GEnum opts (Rep a)) => Int
forall opts a. (Generic a, GEnum opts (Rep a)) => Int
genumMax @opts @a

-- | Generic 'enumFromTo'. Use 'genumFromTo' or 'gfiniteEnumFromTo' instead.
genumFromTo' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> [a]
genumFromTo' :: a -> a -> [a]
genumFromTo' a
x a
y = (Int -> a) -> [Int] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map Int -> a
toE [ Int
i_x .. Int
i_y ]
  where
    toE :: Int -> a
toE = forall a. (Generic a, GEnum opts (Rep a)) => Int -> a
forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
gtoEnumRaw' @opts
    i_x :: Int
i_x = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
x
    i_y :: Int
i_y = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
y

-- | Generic 'enumFromThenTo'. Use 'genumFromThenTo' or 'gfiniteEnumFromThenTo' instead.
genumFromThenTo' :: forall opts a. (Generic a, GEnum opts (Rep a)) => a -> a -> a -> [a]
genumFromThenTo' :: a -> a -> a -> [a]
genumFromThenTo' a
x1 a
x2 a
y = (Int -> a) -> [Int] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map Int -> a
toE [ Int
i_x1, Int
i_x2 .. Int
i_y ]
  where
    toE :: Int -> a
toE  = forall a. (Generic a, GEnum opts (Rep a)) => Int -> a
forall opts a. (Generic a, GEnum opts (Rep a)) => Int -> a
gtoEnumRaw' @opts
    i_x1 :: Int
i_x1 = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
x1
    i_x2 :: Int
i_x2 = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
x2
    i_y :: Int
i_y  = a -> Int
forall opts a. (Generic a, GEnum opts (Rep a)) => a -> Int
gfromEnum'  @opts a
y

-- | Generic 'minBound'.
--
-- @
-- instance 'Bounded' MyType where
--   'minBound' = 'gminBound'
--   'maxBound' = 'gmaxBound'
-- @
gminBound :: (Generic a, GBounded (Rep a)) => a
gminBound :: a
gminBound = Rep a Any -> a
forall a x. Generic a => Rep a x -> a
to Rep a Any
forall (f :: * -> *) p. GBounded f => f p
gMinBound

-- | Generic 'maxBound'.
--
-- See also 'gminBound'.
gmaxBound :: (Generic a, GBounded (Rep a)) => a
gmaxBound :: a
gmaxBound = Rep a Any -> a
forall a x. Generic a => Rep a x -> a
to Rep a Any
forall (f :: * -> *) p. GBounded f => f p
gMaxBound

-- | Generic 'range'.
--
-- @
-- import "Data.Ix"
-- instance 'Ix' MyType where
--   'range' = 'grange'
--   'index' = 'gindex'
--   'inRange' = 'ginRange'
-- @
grange :: (Generic a, GIx (Rep a)) => (a, a) -> [a]
grange :: (a, a) -> [a]
grange (a
m, a
n) = (Rep a Any -> a) -> [Rep a Any] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map Rep a Any -> a
forall a x. Generic a => Rep a x -> a
to ([Rep a Any] -> [a]) -> [Rep a Any] -> [a]
forall a b. (a -> b) -> a -> b
$ (Rep a Any, Rep a Any) -> [Rep a Any]
forall (f :: * -> *) p. GIx f => (f p, f p) -> [f p]
gRange (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
m, a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
n)

-- | Generic 'index'.
--
-- See also 'grange'.
gindex :: (Generic a, GIx (Rep a)) => (a, a) -> a -> Int
gindex :: (a, a) -> a -> Int
gindex (a, a)
b a
i
  | (a, a) -> a -> Bool
forall a. (Generic a, GIx (Rep a)) => (a, a) -> a -> Bool
ginRange (a, a)
b a
i = (a, a) -> a -> Int
forall a. (Generic a, GIx (Rep a)) => (a, a) -> a -> Int
gunsafeIndex (a, a)
b a
i
  | Bool
otherwise = String -> Int
forall a. String -> a
errorWithoutStackTrace String
"gindex: out of bounds"

-- | Generic @unsafeIndex@.
--
-- === __Details__
--
-- The functions @unsafeIndex@ and @unsafeRangeSize@ belong to 'Ix' but are
-- internal to GHC and hence not exported from the module "Data.Ix". However they
-- are exported from the module @GHC.Arr@.
-- See 'grange' for how to define an instance of 'Ix' such that it does not
-- depend on the stability of GHCs internal API. Unfortunately this results in
-- additional (unnecessary) bound checks.
-- With the danger of having no stability guarantees for GHC's internal API one
-- can alternatively define an instance of 'Ix' as
--
-- @
-- import GHC.Arr
-- instance 'Ix' MyType where
--   'range' = 'grange'
--   unsafeIndex = 'gunsafeIndex'
--   'inRange' = 'ginRange'
-- @
gunsafeIndex :: (Generic a, GIx (Rep a)) => (a, a) -> a -> Int
gunsafeIndex :: (a, a) -> a -> Int
gunsafeIndex (a
m, a
n) a
i = (Rep a Any, Rep a Any) -> Rep a Any -> Int
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Int
gUnsafeIndex (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
m, a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
n) (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
i)

-- | Generic 'inRange'.
--
-- See also 'grange'.
ginRange :: (Generic a, GIx (Rep a)) => (a, a) -> a -> Bool
ginRange :: (a, a) -> a -> Bool
ginRange (a
m, a
n) a
i = (Rep a Any, Rep a Any) -> Rep a Any -> Bool
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Bool
gInRange (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
m, a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
n) (a -> Rep a Any
forall a x. Generic a => a -> Rep a x
from a
i)

-- | Generic representation of 'Enum' types.
--
-- The @opts@ parameter is a type-level option to select different
-- implementations.
class GEnum opts f where
  gCardinality :: Int
  gFromEnum :: f p -> Int
  gToEnum :: Int -> f p

-- | Standard option for 'GEnum': derive 'Enum' for types with only nullary
-- constructors (the same restrictions as in the [Haskell 2010
-- report](https://www.haskell.org/onlinereport/haskell2010/haskellch11.html#x18-18400011.2)).
data StandardEnum

-- | Extends the 'StandardEnum' option for 'GEnum' to allow all constructors to 
-- have arbitrary many fields. Each field type must be an instance of 
-- both 'Enum' and 'Bounded'.
--
-- === __Details__
--
-- Two restrictions require the user's caution:
--
-- * The 'Enum' instances of the field types need to start enumerating from 0. 
-- Particularly 'Int' is an unfit field type, because the enumeration of the 
-- negative values starts before 0. 
--
-- * There can only be up to @'maxBound' :: 'Int'@ values (because the implementation
-- represents the cardinality explicitly as an 'Int'). This restriction makes
-- 'Word' an invalid field type. Notably, it is insufficient for each
-- individual field types to stay below this limit. Instead it applies to the
-- generic type as a whole.
--
-- The resulting 'GEnum' instance starts enumerating from @0@ up to
-- @(cardinality - 1)@ and respects the generic 'Ord' instance (defined by
-- 'Generic.Data.gcompare'). The values from different constructors are enumerated
-- sequentially; they are not interleaved.
--
-- @
-- data Example = C0 Bool Bool | C1 Bool
--   deriving ('Eq', 'Ord', 'Show', 'Generic')
--
-- cardinality = 6  -- 2    * 2    + 2
--                  -- Bool * Bool | Bool
--
-- enumeration =
--     [ C0 False False
--     , C0 False  True
--     , C0  True False
--     , C0  True  True
--     , C1 False
--     , C1 True
--     ]
--
-- enumeration == map 'gtoFiniteEnum' [0 .. 5]
-- [0 .. 5] == map 'gfromFiniteEnum' enumeration
-- @
data FiniteEnum

instance GEnum opts f => GEnum opts (M1 i c f) where
  gCardinality :: Int
gCardinality = GEnum opts f => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @f
  gFromEnum :: M1 i c f p -> Int
gFromEnum = forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
forall (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @opts (f p -> Int) -> (M1 i c f p -> f p) -> M1 i c f p -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. M1 i c f p -> f p
forall i (c :: Meta) k (f :: k -> *) (p :: k). M1 i c f p -> f p
unM1
  gToEnum :: Int -> M1 i c f p
gToEnum = f p -> M1 i c f p
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 (f p -> M1 i c f p) -> (Int -> f p) -> Int -> M1 i c f p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
forall (f :: * -> *) p. GEnum opts f => Int -> f p
gToEnum @opts

instance (GEnum opts f, GEnum opts g) => GEnum opts (f :+: g) where
  gCardinality :: Int
gCardinality = GEnum opts f => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @f Int -> Int -> Int
forall a. Num a => a -> a -> a
+ GEnum opts g => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @g
  gFromEnum :: (:+:) f g p -> Int
gFromEnum (L1 f p
x) = f p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @opts f p
x
  gFromEnum (R1 g p
y) = Int
cardF Int -> Int -> Int
forall a. Num a => a -> a -> a
+ g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @opts g p
y
    where
      cardF :: Int
cardF = GEnum opts f => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @f
  gToEnum :: Int -> (:+:) f g p
gToEnum Int
n
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
cardF = f p -> (:+:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k). f p -> (:+:) f g p
L1 (Int -> f p
forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
gToEnum @opts Int
n)
    | Bool
otherwise = g p -> (:+:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k). g p -> (:+:) f g p
R1 (Int -> g p
forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
gToEnum @opts (Int
n Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
cardF))
    where
      cardF :: Int
cardF = GEnum opts f => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @opts @f

instance (GEnum FiniteEnum f, GEnum FiniteEnum g) => GEnum FiniteEnum (f :*: g) where
  gCardinality :: Int
gCardinality = GEnum FiniteEnum f => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @FiniteEnum @f Int -> Int -> Int
forall a. Num a => a -> a -> a
* GEnum FiniteEnum g => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @FiniteEnum @g
  gFromEnum :: (:*:) f g p -> Int
gFromEnum (f p
x :*: g p
y) = f p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @FiniteEnum f p
x Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
cardG Int -> Int -> Int
forall a. Num a => a -> a -> a
+ g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @FiniteEnum g p
y
    where
      cardG :: Int
cardG = GEnum FiniteEnum g => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @FiniteEnum @g
  gToEnum :: Int -> (:*:) f g p
gToEnum Int
n = Int -> f p
forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
gToEnum @FiniteEnum Int
x f p -> g p -> (:*:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: Int -> g p
forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
gToEnum @FiniteEnum Int
y
    where
      (Int
x, Int
y) = Int
n Int -> Int -> (Int, Int)
forall a. Integral a => a -> a -> (a, a)
`quotRem` Int
cardG
      cardG :: Int
cardG = GEnum FiniteEnum g => Int
forall opts (f :: * -> *). GEnum opts f => Int
gCardinality @FiniteEnum @g
  
instance GEnum opts U1 where
  gCardinality :: Int
gCardinality = Int
1
  gFromEnum :: U1 p -> Int
gFromEnum U1 p
U1 = Int
0
  gToEnum :: Int -> U1 p
gToEnum Int
_ = U1 p
forall k (p :: k). U1 p
U1

instance (Bounded c, Enum c) => GEnum FiniteEnum (K1 i c) where
  gCardinality :: Int
gCardinality = c -> Int
forall a. Enum a => a -> Int
fromEnum (c
forall a. Bounded a => a
maxBound :: c) Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
  gFromEnum :: K1 i c p -> Int
gFromEnum = c -> Int
forall a. Enum a => a -> Int
fromEnum (c -> Int) -> (K1 i c p -> c) -> K1 i c p -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. K1 i c p -> c
forall i c k (p :: k). K1 i c p -> c
unK1
  gToEnum :: Int -> K1 i c p
gToEnum = c -> K1 i c p
forall k i c (p :: k). c -> K1 i c p
K1 (c -> K1 i c p) -> (Int -> c) -> Int -> K1 i c p
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> c
forall a. Enum a => Int -> a
toEnum

-- | Generic representation of 'Bounded' types.
class GBounded f where
  gMinBound :: f p
  gMaxBound :: f p

deriving instance GBounded f => GBounded (M1 i c f)

instance GBounded U1 where
  gMinBound :: U1 p
gMinBound = U1 p
forall k (p :: k). U1 p
U1
  gMaxBound :: U1 p
gMaxBound = U1 p
forall k (p :: k). U1 p
U1

instance Bounded c => GBounded (K1 i c) where
  gMinBound :: K1 i c p
gMinBound = c -> K1 i c p
forall k i c (p :: k). c -> K1 i c p
K1 c
forall a. Bounded a => a
minBound
  gMaxBound :: K1 i c p
gMaxBound = c -> K1 i c p
forall k i c (p :: k). c -> K1 i c p
K1 c
forall a. Bounded a => a
maxBound

instance (GBounded f, GBounded g) => GBounded (f :+: g) where
  gMinBound :: (:+:) f g p
gMinBound = f p -> (:+:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k). f p -> (:+:) f g p
L1 f p
forall (f :: * -> *) p. GBounded f => f p
gMinBound
  gMaxBound :: (:+:) f g p
gMaxBound = g p -> (:+:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k). g p -> (:+:) f g p
R1 g p
forall (f :: * -> *) p. GBounded f => f p
gMaxBound

instance (GBounded f, GBounded g) => GBounded (f :*: g) where
  gMinBound :: (:*:) f g p
gMinBound = f p
forall (f :: * -> *) p. GBounded f => f p
gMinBound f p -> g p -> (:*:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: g p
forall (f :: * -> *) p. GBounded f => f p
gMinBound
  gMaxBound :: (:*:) f g p
gMaxBound = f p
forall (f :: * -> *) p. GBounded f => f p
gMaxBound f p -> g p -> (:*:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: g p
forall (f :: * -> *) p. GBounded f => f p
gMaxBound

-- | Generic representation of 'Ix' types.
--
class GIx f where
  gRange :: (f p, f p) -> [f p]
  gUnsafeIndex :: (f p, f p) -> f p -> Int
  gInRange :: (f p, f p) -> f p -> Bool

instance GIx f => GIx (M1 i c f) where
  gRange :: (M1 i c f p, M1 i c f p) -> [M1 i c f p]
gRange (M1 f p
m, M1 f p
n) = (f p -> M1 i c f p) -> [f p] -> [M1 i c f p]
forall a b. (a -> b) -> [a] -> [b]
map f p -> M1 i c f p
forall k i (c :: Meta) (f :: k -> *) (p :: k). f p -> M1 i c f p
M1 ([f p] -> [M1 i c f p]) -> [f p] -> [M1 i c f p]
forall a b. (a -> b) -> a -> b
$ (f p, f p) -> [f p]
forall (f :: * -> *) p. GIx f => (f p, f p) -> [f p]
gRange (f p
m, f p
n)
  gUnsafeIndex :: (M1 i c f p, M1 i c f p) -> M1 i c f p -> Int
gUnsafeIndex (M1 f p
m, M1 f p
n) (M1 f p
i) = (f p, f p) -> f p -> Int
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Int
gUnsafeIndex (f p
m, f p
n) f p
i
  gInRange :: (M1 i c f p, M1 i c f p) -> M1 i c f p -> Bool
gInRange (M1 f p
m, M1 f p
n) (M1 f p
i) = (f p, f p) -> f p -> Bool
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Bool
gInRange (f p
m, f p
n) f p
i

instance (GEnum StandardEnum f, GEnum StandardEnum g) => GIx (f :+: g) where
  gRange :: ((:+:) f g p, (:+:) f g p) -> [(:+:) f g p]
gRange ((:+:) f g p
x, (:+:) f g p
y) = (Int -> (:+:) f g p) -> [Int] -> [(:+:) f g p]
forall a b. (a -> b) -> [a] -> [b]
map Int -> (:+:) f g p
forall p. Int -> (:+:) f g p
toE [ Int
i_x .. Int
i_y ]
    where
      toE :: Int -> (:+:) f g p
toE = forall opts (f :: * -> *) p. GEnum opts f => Int -> f p
forall (f :: * -> *) p. GEnum StandardEnum f => Int -> f p
gToEnum @StandardEnum
      i_x :: Int
i_x = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
x
      i_y :: Int
i_y = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
y
  gUnsafeIndex :: ((:+:) f g p, (:+:) f g p) -> (:+:) f g p -> Int
gUnsafeIndex ((:+:) f g p
m, (:+:) f g p
_) (:+:) f g p
i = Int -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Int
i_i Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
i_m)
    where
      i_m :: Int
i_m = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
m
      i_i :: Int
i_i = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
i
  gInRange :: ((:+:) f g p, (:+:) f g p) -> (:+:) f g p -> Bool
gInRange ((:+:) f g p
m, (:+:) f g p
n) (:+:) f g p
i = Int
i_m Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i_i Bool -> Bool -> Bool
&& Int
i_i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
i_n
    where
      i_m :: Int
i_m = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
m
      i_n :: Int
i_n = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
n
      i_i :: Int
i_i = (:+:) f g p -> Int
forall opts (f :: * -> *) p. GEnum opts f => f p -> Int
gFromEnum @StandardEnum (:+:) f g p
i

instance (GIx f, GIx g) => GIx (f :*: g) where
  gRange :: ((:*:) f g p, (:*:) f g p) -> [(:*:) f g p]
gRange (f p
m1 :*: g p
m2, f p
n1 :*: g p
n2) =
    [ f p
i1 f p -> g p -> (:*:) f g p
forall k (f :: k -> *) (g :: k -> *) (p :: k).
f p -> g p -> (:*:) f g p
:*: g p
i2 | f p
i1 <- (f p, f p) -> [f p]
forall (f :: * -> *) p. GIx f => (f p, f p) -> [f p]
gRange (f p
m1, f p
n1), g p
i2 <- (g p, g p) -> [g p]
forall (f :: * -> *) p. GIx f => (f p, f p) -> [f p]
gRange (g p
m2, g p
n2) ]
  gUnsafeIndex :: ((:*:) f g p, (:*:) f g p) -> (:*:) f g p -> Int
gUnsafeIndex (f p
m1 :*: g p
m2, f p
n1 :*: g p
n2) (f p
i1 :*: g p
i2) = Int
int1 Int -> Int -> Int
forall a. Num a => a -> a -> a
* Int
rangeSize2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
int2
    where
      int1 :: Int
int1 = (f p, f p) -> f p -> Int
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Int
gUnsafeIndex (f p
m1, f p
n1) f p
i1
      int2 :: Int
int2 = (g p, g p) -> g p -> Int
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Int
gUnsafeIndex (g p
m2, g p
n2) g p
i2
      rangeSize2 :: Int
rangeSize2 = (g p, g p) -> g p -> Int
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Int
gUnsafeIndex (g p
m2, g p
n2) g p
n2 Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
  gInRange :: ((:*:) f g p, (:*:) f g p) -> (:*:) f g p -> Bool
gInRange (f p
m1 :*: g p
m2, f p
n1 :*: g p
n2) (f p
i1 :*: g p
i2) =
    (f p, f p) -> f p -> Bool
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Bool
gInRange (f p
m1, f p
n1) f p
i1 Bool -> Bool -> Bool
&& (g p, g p) -> g p -> Bool
forall (f :: * -> *) p. GIx f => (f p, f p) -> f p -> Bool
gInRange (g p
m2, g p
n2) g p
i2
  
instance GIx U1 where
  gRange :: (U1 p, U1 p) -> [U1 p]
gRange (U1 p
U1, U1 p
U1) = [U1 p
forall k (p :: k). U1 p
U1]
  gUnsafeIndex :: (U1 p, U1 p) -> U1 p -> Int
gUnsafeIndex (U1 p
U1, U1 p
U1) U1 p
U1 = Int
0
  gInRange :: (U1 p, U1 p) -> U1 p -> Bool
gInRange (U1 p
U1, U1 p
U1) U1 p
U1 = Bool
True

instance (Ix c) => GIx (K1 i c) where
  gRange :: (K1 i c p, K1 i c p) -> [K1 i c p]
gRange (K1 c
m, K1 c
n) = (c -> K1 i c p) -> [c] -> [K1 i c p]
forall a b. (a -> b) -> [a] -> [b]
map c -> K1 i c p
forall k i c (p :: k). c -> K1 i c p
K1 ([c] -> [K1 i c p]) -> [c] -> [K1 i c p]
forall a b. (a -> b) -> a -> b
$ (c, c) -> [c]
forall a. Ix a => (a, a) -> [a]
range (c
m, c
n)
  gUnsafeIndex :: (K1 i c p, K1 i c p) -> K1 i c p -> Int
gUnsafeIndex (K1 c
m, K1 c
n) (K1 c
i) = (c, c) -> c -> Int
forall a. Ix a => (a, a) -> a -> Int
index (c
m, c
n) c
i 
  gInRange :: (K1 i c p, K1 i c p) -> K1 i c p -> Bool
gInRange (K1 c
m, K1 c
n) (K1 c
i) = (c, c) -> c -> Bool
forall a. Ix a => (a, a) -> a -> Bool
inRange (c
m, c
n) c
i