-- | C enumerations
--
-- This module is intended to be imported qualified.
--
-- > import HsBindgen.Runtime.Prelude
-- > import HsBindgen.Runtime.CEnum qualified as CEnum
module HsBindgen.Runtime.CEnum (
    -- * Type classes
    CEnum(..)
  , SequentialCEnum(..)
    -- * Deriving via support
  , AsCEnum(..)
  , AsSequentialCEnum(..)
    -- * API
  , getNames
    -- * Instance support
  , DeclaredValues
  , declaredValuesFromList
  , show
  , shows
  , showsWrappedUndeclared
  , readEither
  , readPrec
  , readPrecWrappedUndeclared
  , seqIsDeclared
  , seqMkDeclared
    -- ** Exceptions
  , CEnumException(..)
  ) where

import Prelude hiding (show, shows)
import Prelude qualified

import Control.Exception (Exception (displayException), throw)
import Data.Bifunctor (Bifunctor (first))
import Data.Coerce (Coercible, coerce)
import Data.List qualified as List
import Data.List.NonEmpty (NonEmpty ((:|)))
import Data.List.NonEmpty qualified as NonEmpty
import Data.Map.Strict (Map)
import Data.Map.Strict qualified as Map
import Data.Proxy (Proxy (Proxy))
import GHC.Show (appPrec, appPrec1, showSpace)
import Text.ParserCombinators.ReadP qualified as ReadP
import Text.ParserCombinators.ReadPrec qualified as ReadPrec
import Text.Read (ReadPrec, minPrec, (+++))
import Text.Read qualified as Read
import Text.Read.Lex (Lexeme (..), expect)

{-------------------------------------------------------------------------------
  Type classes
-------------------------------------------------------------------------------}

-- | C enumeration
--
-- This class implements an API for Haskell representations of C enumerations.
-- C @enum@ declarations only declare values; they do not limit the range of the
-- corresponding integral type.  They may have negative values, non-sequential
-- values, and multiple names for a single value.
--
-- At a low level, @hs-bindgen@ generates a @newtype@ wrapper around the
-- integral representation type to represent a C @enum@.  An instance of this
-- class is generated automatically.  A 'Show' instance defined using
-- 'showsCEnum' is also generated by default.  'Bounded' and 'Enum' instances are
-- /not/ generated automatically because values do not technically need to be
-- declared.  Users may optionally derive these instances using 'AsCEnum' or
-- 'AsSeqentialCEnum' when appropriate.
--
-- This class may also be used with Haskell sum-type representations of
-- enumerations.
class Integral (CEnumZ a) => CEnum a where
  -- | Integral representation type
  type CEnumZ a

  -- | Construct a value from the integral representation
  --
  -- prop> fromCEnum . toCEnum === id
  toCEnum :: CEnumZ a -> a
  default toCEnum :: Coercible a (CEnumZ a) => CEnumZ a -> a
  toCEnum = CEnumZ a -> a
forall a b. Coercible a b => a -> b
coerce

  -- | Get the integral representation for a value
  --
  -- prop> toCEnum . fromCEnum === id
  --
  -- If @a@ has an 'Ord' instance, it should be compatible with the 'Ord'
  -- instance on the underlying integral value:
  --
  -- prop> \x y -> (x <= y) === (fromCEnum x <= fromCEnum y)
  fromCEnum :: a -> CEnumZ a
  default fromCEnum :: Coercible a (CEnumZ a) => a -> CEnumZ a
  fromCEnum = a -> CEnumZ a
forall a b. Coercible a b => a -> b
coerce

  -- | Declared values and associated names
  declaredValues :: proxy a -> DeclaredValues a

  -- | Show undeclared value
  --
  -- Like any 'Show' related function, this should generate a valid Haskell
  -- expression. In this case, a valid Haskell expression for values /outside/
  -- of the set of declared values (that is, for which 'isDeclared' will return
  -- 'False').
  --
  -- The default definition just shows the underlying integer value; this is
  -- valid if the Haskell wrapper has a 'Num' instance. If the Haskell type is
  -- simply a newtype wrapper around the underlying C type, you can use
  -- 'showsWrappedUndeclared'. Finally, if the Haskell type /cannot/ represent
  -- undeclared values, this can be defined using @error@.
  --
  -- > showsUndeclared _ = \_ x ->
  -- >   error $ "Unexpected value " ++ show x ++ " for type Foo"
  showsUndeclared :: proxy a -> Int -> CEnumZ a -> ShowS
  default showsUndeclared ::
               Show (CEnumZ a)
            => proxy a -> Int -> CEnumZ a -> ShowS
  showsUndeclared proxy a
_ = Int -> CEnumZ a -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec

  -- | Read undeclared value
  --
  -- See 'showsUndeclared', 'showsWrappedUndeclared', and
  -- 'readPrecWrappedUndeclared'.
  readPrecUndeclared :: ReadPrec a

  -- | Determine if the specified value is declared
  --
  -- This has a default definition in terms of 'getDeclaredValues', but you may
  -- wish to override this with a more efficient implementation (in particular,
  -- see 'seqIsDeclared').
  isDeclared :: a -> Bool
  isDeclared a
x = (a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x) CEnumZ a -> Map (CEnumZ a) (NonEmpty String) -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a)

  -- | Construct a value only if it is declared
  --
  -- See also 'seqMkDeclared'.
  mkDeclared :: CEnumZ a -> Maybe a
  mkDeclared CEnumZ a
i
    | CEnumZ a
i CEnumZ a -> Map (CEnumZ a) (NonEmpty String) -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a) = a -> Maybe a
forall a. a -> Maybe a
Just (CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
i)
    | Bool
otherwise = Maybe a
forall a. Maybe a
Nothing

-- | C enumeration with sequential values
--
-- 'Bounded' and 'Enum' methods may be implemented more efficiently when the
-- values of an enumeration are sequential.  An instance of this class is
-- generated automatically in this case.  Users may optionally derive these
-- instances using 'AsSequentialCEnum' when appropriate.
--
-- This class may also be used with Haskell sum-type representations of
-- enumerations.
--
-- prop> all isDeclared [minDeclaredValue..maxDeclaredValue]
class CEnum a => SequentialCEnum a where
  -- | The minimum declared value
  --
  -- prop> minDeclaredValue == minimum (filter isDeclared (map toCEnum [minBound..]))
  minDeclaredValue :: a

  -- | The maximum declared value
  --
  -- prop> maxDeclaredValue == maximum (filter isDeclared (map toCEnum [minBound..]))
  maxDeclaredValue :: a

{-------------------------------------------------------------------------------
  API
-------------------------------------------------------------------------------}

-- | Get all names associated with a value
--
-- An empty list is returned when the specified value is not declared.
getNames :: forall a. CEnum a => a -> [String]
getNames :: forall a. CEnum a => a -> [String]
getNames a
x = [String]
-> (NonEmpty String -> [String])
-> Maybe (NonEmpty String)
-> [String]
forall b a. b -> (a -> b) -> Maybe a -> b
maybe [] NonEmpty String -> [String]
forall a. NonEmpty a -> [a]
NonEmpty.toList (Maybe (NonEmpty String) -> [String])
-> Maybe (NonEmpty String) -> [String]
forall a b. (a -> b) -> a -> b
$
    CEnumZ a
-> Map (CEnumZ a) (NonEmpty String) -> Maybe (NonEmpty String)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup (a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x) (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))

{-------------------------------------------------------------------------------
  Instance support
-------------------------------------------------------------------------------}

-- | Declared values (opaque)
data DeclaredValues a = DeclaredValues
    { forall a. DeclaredValues a -> Map (CEnumZ a) (NonEmpty String)
integralToDeclaredValues :: !(Map (CEnumZ a) (NonEmpty String))
    , forall a. DeclaredValues a -> Map String (CEnumZ a)
declaredValueToIntegral :: !(Map String (CEnumZ a))
    }

-- | Construct 'DeclaredValues' from a list of values and associated names
declaredValuesFromList ::
     Ord (CEnumZ a)
  => [(CEnumZ a, NonEmpty String)]
  -> DeclaredValues a
declaredValuesFromList :: forall a.
Ord (CEnumZ a) =>
[(CEnumZ a, NonEmpty String)] -> DeclaredValues a
declaredValuesFromList [(CEnumZ a, NonEmpty String)]
xs =
  DeclaredValues
    { integralToDeclaredValues :: Map (CEnumZ a) (NonEmpty String)
integralToDeclaredValues = [(CEnumZ a, NonEmpty String)] -> Map (CEnumZ a) (NonEmpty String)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(CEnumZ a, NonEmpty String)]
xs
    , declaredValueToIntegral :: Map String (CEnumZ a)
declaredValueToIntegral =
        [(String, CEnumZ a)] -> Map String (CEnumZ a)
forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [ (String
n, CEnumZ a
i) | (CEnumZ a
i, NonEmpty String
ns) <-  [(CEnumZ a, NonEmpty String)]
xs , String
n <- NonEmpty String -> [String]
forall a. NonEmpty a -> [a]
NonEmpty.toList NonEmpty String
ns ] }

declaredValuesList :: DeclaredValues a -> [String]
declaredValuesList :: forall a. DeclaredValues a -> [String]
declaredValuesList = Map String (CEnumZ a) -> [String]
forall k a. Map k a -> [k]
Map.keys (Map String (CEnumZ a) -> [String])
-> (DeclaredValues a -> Map String (CEnumZ a))
-> DeclaredValues a
-> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. DeclaredValues a -> Map String (CEnumZ a)
forall a. DeclaredValues a -> Map String (CEnumZ a)
declaredValueToIntegral

-- | Show the specified value
--
-- Examples for a hypothetical enumeration type, using generated defaults:
--
-- > showCEnum StatusOK == "StatusOK"
--
-- > showCEnum (StatusCode 418) == "StatusCode 418"
show :: forall a. CEnum a => a -> String
show :: forall a. CEnum a => a -> String
show a
x = Int -> a -> ShowS
forall a. CEnum a => Int -> a -> ShowS
shows Int
0 a
x String
""

-- | Generalization of 'showCEnum' (akin to 'showsPrec').
--
-- This function may be used in the definition of a 'Show' instance for a
-- @newtype@ representation of a C enumeration.
--
-- When the value is declared, a corresponding name is returned.  Otherwise,
-- 'showsUndeclared' is called.
shows :: forall a. CEnum a => Int -> a -> ShowS
shows :: forall a. CEnum a => Int -> a -> ShowS
shows Int
prec a
x =
    case CEnumZ a
-> Map (CEnumZ a) (NonEmpty String) -> Maybe (NonEmpty String)
forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a)) of
      Just (String
name :| [String]
_names) -> String -> ShowS
showString String
name
      Maybe (NonEmpty String)
Nothing -> Proxy a -> Int -> CEnumZ a -> ShowS
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Int -> CEnumZ a -> ShowS
forall (proxy :: * -> *). proxy a -> Int -> CEnumZ a -> ShowS
showsUndeclared (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a) Int
prec CEnumZ a
i
  where
    i :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

-- | Read a 'CEnum' from string
--
-- Examples for a hypothetical enumeration type, using generated defaults:
--
-- > (readEitherCEnum "StatusCode 200" :: StatusCode) == Right StatusOK
--
-- > (readEitherCEnum "StatusOK" :: StatusCode) == Right StatusOK
--
-- > (readEitherCEnum "StatusCode 123" :: StatusCode) == Right (StatusCode 123)
readEither :: forall a. CEnum a => String -> Either String a
readEither :: forall a. CEnum a => String -> Either String a
readEither String
s =
  case [ a
x | (a
x,String
"") <- ReadPrec a -> Int -> ReadS a
forall a. ReadPrec a -> Int -> ReadS a
ReadPrec.readPrec_to_S ReadPrec a
read' Int
minPrec String
s ] of
    [a
x] -> a -> Either String a
forall a b. b -> Either a b
Right a
x
    []  -> String -> Either String a
forall a b. a -> Either a b
Left String
"readEitherCEnum: no parse"
    [a]
_xs -> String -> Either String a
forall a b. a -> Either a b
Left String
"readEitherCEnum: ambiguous parse"
 where
  read' :: ReadPrec a
read' =
    do a
x <- ReadPrec a
forall a. CEnum a => ReadPrec a
readPrec
       ReadP () -> ReadPrec ()
forall a. ReadP a -> ReadPrec a
ReadPrec.lift ReadP ()
ReadP.skipSpaces
       a -> ReadPrec a
forall a. a -> ReadPrec a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x

-- | Helper function for defining 'showsUndeclared'
--
-- This helper can be used in the case where @a@ is a newtype wrapper around
-- the underlying @CEnumZ a@.
showsWrappedUndeclared ::
     Show (CEnumZ a)
  => String -> proxy a -> Int -> CEnumZ a -> ShowS
showsWrappedUndeclared :: forall a (proxy :: * -> *).
Show (CEnumZ a) =>
String -> proxy a -> Int -> CEnumZ a -> ShowS
showsWrappedUndeclared String
constructorName proxy a
_ Int
p CEnumZ a
x = Bool -> ShowS -> ShowS
showParen (Int
p Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
appPrec1) (ShowS -> ShowS) -> ShowS -> ShowS
forall a b. (a -> b) -> a -> b
$
     String -> ShowS
showString String
constructorName
   ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ShowS
showSpace
   ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> CEnumZ a -> ShowS
forall a. Show a => Int -> a -> ShowS
showsPrec Int
appPrec1 CEnumZ a
x

-- | Read a declared 'CEnum' value
readPrecDeclaredValue :: forall proxy a. CEnum a => proxy a -> ReadPrec a
readPrecDeclaredValue :: forall (proxy :: * -> *) a. CEnum a => proxy a -> ReadPrec a
readPrecDeclaredValue proxy a
proxy = ReadPrec a -> ReadPrec a
forall a. ReadPrec a -> ReadPrec a
Read.parens (ReadPrec a -> ReadPrec a) -> ReadPrec a -> ReadPrec a
forall a b. (a -> b) -> a -> b
$ Int -> ReadPrec a -> ReadPrec a
forall a. Int -> ReadPrec a -> ReadPrec a
ReadPrec.prec Int
appPrec1 (ReadPrec a -> ReadPrec a) -> ReadPrec a -> ReadPrec a
forall a b. (a -> b) -> a -> b
$ do
  String
declaredValue <- ReadP String -> ReadPrec String
forall a. ReadP a -> ReadPrec a
ReadPrec.lift (ReadP String -> ReadPrec String)
-> ReadP String -> ReadPrec String
forall a b. (a -> b) -> a -> b
$ [ReadP String] -> ReadP String
forall a. [ReadP a] -> ReadP a
ReadP.choice ([ReadP String] -> ReadP String) -> [ReadP String] -> ReadP String
forall a b. (a -> b) -> a -> b
$
                     (String -> ReadP String) -> [String] -> [ReadP String]
forall a b. (a -> b) -> [a] -> [b]
map String -> ReadP String
ReadP.string ([String] -> [ReadP String]) -> [String] -> [ReadP String]
forall a b. (a -> b) -> a -> b
$ DeclaredValues a -> [String]
forall a. DeclaredValues a -> [String]
declaredValuesList (DeclaredValues a -> [String]) -> DeclaredValues a -> [String]
forall a b. (a -> b) -> a -> b
$ proxy a -> DeclaredValues a
forall a (proxy :: * -> *). CEnum a => proxy a -> DeclaredValues a
forall (proxy :: * -> *). proxy a -> DeclaredValues a
declaredValues proxy a
proxy
  a -> ReadPrec a
forall a. a -> ReadPrec a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> ReadPrec a) -> a -> ReadPrec a
forall a b. (a -> b) -> a -> b
$ CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a -> a) -> CEnumZ a -> a
forall a b. (a -> b) -> a -> b
$ (DeclaredValues a -> Map String (CEnumZ a)
forall a. DeclaredValues a -> Map String (CEnumZ a)
declaredValueToIntegral (DeclaredValues a -> Map String (CEnumZ a))
-> DeclaredValues a -> Map String (CEnumZ a)
forall a b. (a -> b) -> a -> b
$ proxy a -> DeclaredValues a
forall a (proxy :: * -> *). CEnum a => proxy a -> DeclaredValues a
forall (proxy :: * -> *). proxy a -> DeclaredValues a
declaredValues proxy a
proxy) Map String (CEnumZ a) -> String -> CEnumZ a
forall k a. Ord k => Map k a -> k -> a
Map.! String
declaredValue

-- | Helper function for defining 'readPrecUndeclared'
--
-- This helper can be used in the case where @a@ is a newtype wrapper around
-- the underlying @CEnumZ a@.
readPrecWrappedUndeclared
  :: forall a. (CEnum a, Read (CEnumZ a)) => String -> ReadPrec a
readPrecWrappedUndeclared :: forall a. (CEnum a, Read (CEnumZ a)) => String -> ReadPrec a
readPrecWrappedUndeclared String
constructorName = ReadPrec a -> ReadPrec a
forall a. ReadPrec a -> ReadPrec a
Read.parens (ReadPrec a -> ReadPrec a) -> ReadPrec a -> ReadPrec a
forall a b. (a -> b) -> a -> b
$ Int -> ReadPrec a -> ReadPrec a
forall a. Int -> ReadPrec a -> ReadPrec a
ReadPrec.prec Int
appPrec (ReadPrec a -> ReadPrec a) -> ReadPrec a -> ReadPrec a
forall a b. (a -> b) -> a -> b
$ do
  ReadP () -> ReadPrec ()
forall a. ReadP a -> ReadPrec a
ReadPrec.lift (ReadP () -> ReadPrec ()) -> ReadP () -> ReadPrec ()
forall a b. (a -> b) -> a -> b
$ Lexeme -> ReadP ()
expect (Lexeme -> ReadP ()) -> Lexeme -> ReadP ()
forall a b. (a -> b) -> a -> b
$ String -> Lexeme
Ident String
constructorName
  CEnumZ a
n <- ReadPrec (CEnumZ a) -> ReadPrec (CEnumZ a)
forall a. ReadPrec a -> ReadPrec a
Read.step (ReadPrec (CEnumZ a)
forall a. Read a => ReadPrec a
Read.readPrec :: ReadPrec (CEnumZ a))
  a -> ReadPrec a
forall a. a -> ReadPrec a
forall (f :: * -> *) a. Applicative f => a -> f a
pure (a -> ReadPrec a) -> a -> ReadPrec a
forall a b. (a -> b) -> a -> b
$ CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
n

-- | Read a 'CEnum' from string
--
-- This function may be used in the definition of a 'Read' instance for a
-- @newtype@ representation of a C enumeration.
readPrec :: forall a. CEnum a => ReadPrec a
readPrec :: forall a. CEnum a => ReadPrec a
readPrec = Proxy a -> ReadPrec a
forall (proxy :: * -> *) a. CEnum a => proxy a -> ReadPrec a
readPrecDeclaredValue (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a) ReadPrec a -> ReadPrec a -> ReadPrec a
forall a. ReadPrec a -> ReadPrec a -> ReadPrec a
+++ ReadPrec a
forall a. CEnum a => ReadPrec a
readPrecUndeclared

-- | Determine if the specified value is declared
--
-- This implementation is optimized for 'SequentialCEnum'.
seqIsDeclared :: forall a. SequentialCEnum a => a -> Bool
seqIsDeclared :: forall a. SequentialCEnum a => a -> Bool
seqIsDeclared a
x = CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
>= CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
<= CEnumZ a
maxZ
  where
    minZ, maxZ, i :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

-- | Construct a value only if it is declared
--
-- This implementation is optimized for 'SequentialCEnum'.
seqMkDeclared :: forall a. SequentialCEnum a => CEnumZ a -> Maybe a
seqMkDeclared :: forall a. SequentialCEnum a => CEnumZ a -> Maybe a
seqMkDeclared CEnumZ a
i
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
>= CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
<= CEnumZ a
maxZ = a -> Maybe a
forall a. a -> Maybe a
Just (CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
i)
    | Bool
otherwise = Maybe a
forall a. Maybe a
Nothing
  where
    minZ, maxZ :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)

{-------------------------------------------------------------------------------
  Deriving via support
-------------------------------------------------------------------------------}

-- | Type used to derive classes using @DerivingVia@ a type with a 'CEnum'
-- instance
--
-- When the values are sequential, 'AsSequentialCEnum' provides better
-- performance and should therefore be used instead.
--
-- The following classes may be derived:
--
-- * 'Bounded' may be derived using the bounds of the declared values.  This is
--   /not/ derived by default.
-- * 'Enum` may be derived using the bounds of the declared values.  This
--   instance assumes that only the declared values are valid and throws a
--   'CEnumException' if passed a value that is not declared.  This is /not/
--   derived by default.
--
-- For /declared/ values we have
--
-- prop> toEnum   === coerce       . toCENum   . fromIntegral
-- prop> fromEnum === fromIntegral . fromCEnum . coerce
--
-- In addition we guarantee that where 'pred' or 'succ' are defined, we have
--
-- prop> \x -> (pred x < x) && (x < succ x)
newtype AsCEnum a = WrapCEnum { forall a. AsCEnum a -> a
unwrapCEnum :: a }

instance CEnum a => Bounded (AsCEnum a) where
  minBound :: AsCEnum a
minBound = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum a
forall a. CEnum a => a
minBoundGen
  maxBound :: AsCEnum a
maxBound = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum a
forall a. CEnum a => a
maxBoundGen

instance CEnum a => Enum (AsCEnum a) where
  succ :: AsCEnum a -> AsCEnum a
succ = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum (a -> AsCEnum a) -> (AsCEnum a -> a) -> AsCEnum a -> AsCEnum a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. CEnum a => a -> a
succGen (a -> a) -> (AsCEnum a -> a) -> AsCEnum a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsCEnum a -> a
forall a. AsCEnum a -> a
unwrapCEnum
  pred :: AsCEnum a -> AsCEnum a
pred = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum (a -> AsCEnum a) -> (AsCEnum a -> a) -> AsCEnum a -> AsCEnum a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. CEnum a => a -> a
predGen (a -> a) -> (AsCEnum a -> a) -> AsCEnum a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsCEnum a -> a
forall a. AsCEnum a -> a
unwrapCEnum

  toEnum :: Int -> AsCEnum a
toEnum   = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum   (a -> AsCEnum a) -> (Int -> a) -> Int -> AsCEnum a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> a
forall a. CEnum a => Int -> a
toEnumGen
  fromEnum :: AsCEnum a -> Int
fromEnum = a -> Int
forall a. CEnum a => a -> Int
fromEnumGen (a -> Int) -> (AsCEnum a -> a) -> AsCEnum a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsCEnum a -> a
forall a. AsCEnum a -> a
unwrapCEnum

  enumFrom :: AsCEnum a -> [AsCEnum a]
enumFrom (WrapCEnum a
x)                   = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum (a -> AsCEnum a) -> [a] -> [AsCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> [a]
forall a. CEnum a => a -> [a]
enumFromGen a
x
  enumFromThen :: AsCEnum a -> AsCEnum a -> [AsCEnum a]
enumFromThen (WrapCEnum a
x) (WrapCEnum a
y) = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum (a -> AsCEnum a) -> [a] -> [AsCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> a -> [a]
forall a. CEnum a => a -> a -> [a]
enumFromThenGen a
x a
y
  enumFromTo :: AsCEnum a -> AsCEnum a -> [AsCEnum a]
enumFromTo (WrapCEnum a
x) (WrapCEnum a
z)   = a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum (a -> AsCEnum a) -> [a] -> [AsCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> a -> [a]
forall a. CEnum a => a -> a -> [a]
enumFromToGen a
x a
z
  enumFromThenTo :: AsCEnum a -> AsCEnum a -> AsCEnum a -> [AsCEnum a]
enumFromThenTo (WrapCEnum a
x) (WrapCEnum a
y) (WrapCEnum a
z) =
    a -> AsCEnum a
forall a. a -> AsCEnum a
WrapCEnum (a -> AsCEnum a) -> [a] -> [AsCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> a -> a -> [a]
forall a. CEnum a => a -> a -> a -> [a]
enumFromThenToGen a
x a
y a
z

-- | Type used to derive classes using @DerivingVia@ a type with a
-- 'SequentialCEnum' instance
--
-- The following classes may be derived:
--
-- * 'Bounded' may be derived using the bounds of the declared values.  This is
--   /not/ derived by default.
-- * 'Enum` may be derived using the bounds of the declared values.  This
--   instance assumes that only the declared values are valid and throws a
--   'CEnumException' if passed a value that is not declared.  This is /not/
--   derived by default.
--
-- 'AsSequentialCEnum' should have the same properties as 'AsCEnum'.
newtype AsSequentialCEnum a = WrapSequentialCEnum { forall a. AsSequentialCEnum a -> a
unwrapSequentialCEnum :: a }

instance SequentialCEnum a => Bounded (AsSequentialCEnum a) where
  minBound :: AsSequentialCEnum a
minBound = a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum a
forall a. SequentialCEnum a => a
minBoundSeq
  maxBound :: AsSequentialCEnum a
maxBound = a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum a
forall a. SequentialCEnum a => a
maxBoundSeq

instance SequentialCEnum a => Enum (AsSequentialCEnum a) where
  succ :: AsSequentialCEnum a -> AsSequentialCEnum a
succ = a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a)
-> (AsSequentialCEnum a -> a)
-> AsSequentialCEnum a
-> AsSequentialCEnum a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. SequentialCEnum a => a -> a
succSeq (a -> a) -> (AsSequentialCEnum a -> a) -> AsSequentialCEnum a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsSequentialCEnum a -> a
forall a. AsSequentialCEnum a -> a
unwrapSequentialCEnum
  pred :: AsSequentialCEnum a -> AsSequentialCEnum a
pred = a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a)
-> (AsSequentialCEnum a -> a)
-> AsSequentialCEnum a
-> AsSequentialCEnum a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. SequentialCEnum a => a -> a
predSeq (a -> a) -> (AsSequentialCEnum a -> a) -> AsSequentialCEnum a -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsSequentialCEnum a -> a
forall a. AsSequentialCEnum a -> a
unwrapSequentialCEnum

  toEnum :: Int -> AsSequentialCEnum a
toEnum   = a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a)
-> (Int -> a) -> Int -> AsSequentialCEnum a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Int -> a
forall a. SequentialCEnum a => Int -> a
toEnumSeq
  fromEnum :: AsSequentialCEnum a -> Int
fromEnum = a -> Int
forall a. SequentialCEnum a => a -> Int
fromEnumSeq (a -> Int)
-> (AsSequentialCEnum a -> a) -> AsSequentialCEnum a -> Int
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsSequentialCEnum a -> a
forall a. AsSequentialCEnum a -> a
unwrapSequentialCEnum

  enumFrom :: AsSequentialCEnum a -> [AsSequentialCEnum a]
enumFrom (WrapSequentialCEnum a
x) = a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a) -> [a] -> [AsSequentialCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> [a]
forall a. SequentialCEnum a => a -> [a]
enumFromSeq a
x
  enumFromThen :: AsSequentialCEnum a -> AsSequentialCEnum a -> [AsSequentialCEnum a]
enumFromThen (WrapSequentialCEnum a
x) (WrapSequentialCEnum a
y) =
    a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a) -> [a] -> [AsSequentialCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> a -> [a]
forall a. SequentialCEnum a => a -> a -> [a]
enumFromThenSeq a
x a
y
  enumFromTo :: AsSequentialCEnum a -> AsSequentialCEnum a -> [AsSequentialCEnum a]
enumFromTo (WrapSequentialCEnum a
x) (WrapSequentialCEnum a
z) =
    a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a) -> [a] -> [AsSequentialCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> a -> [a]
forall a. SequentialCEnum a => a -> a -> [a]
enumFromToSeq a
x a
z
  enumFromThenTo :: AsSequentialCEnum a
-> AsSequentialCEnum a
-> AsSequentialCEnum a
-> [AsSequentialCEnum a]
enumFromThenTo
    (WrapSequentialCEnum a
x)
    (WrapSequentialCEnum a
y)
    (WrapSequentialCEnum a
z) =
      a -> AsSequentialCEnum a
forall a. a -> AsSequentialCEnum a
WrapSequentialCEnum (a -> AsSequentialCEnum a) -> [a] -> [AsSequentialCEnum a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> a -> a -> a -> [a]
forall a. SequentialCEnum a => a -> a -> a -> [a]
enumFromThenToSeq a
x a
y a
z

{-------------------------------------------------------------------------------
  Exceptions
-------------------------------------------------------------------------------}

-- Exceptions used by optional C enumeration instances
data CEnumException
  = CEnumNotDeclared Integer
  | CEnumNoSuccessor Integer
  | CEnumNoPredecessor Integer
  | CEnumEmpty
  | CEnumFromEqThen Integer
  deriving stock (CEnumException -> CEnumException -> Bool
(CEnumException -> CEnumException -> Bool)
-> (CEnumException -> CEnumException -> Bool) -> Eq CEnumException
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: CEnumException -> CEnumException -> Bool
== :: CEnumException -> CEnumException -> Bool
$c/= :: CEnumException -> CEnumException -> Bool
/= :: CEnumException -> CEnumException -> Bool
Eq, Int -> CEnumException -> ShowS
[CEnumException] -> ShowS
CEnumException -> String
(Int -> CEnumException -> ShowS)
-> (CEnumException -> String)
-> ([CEnumException] -> ShowS)
-> Show CEnumException
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CEnumException -> ShowS
showsPrec :: Int -> CEnumException -> ShowS
$cshow :: CEnumException -> String
show :: CEnumException -> String
$cshowList :: [CEnumException] -> ShowS
showList :: [CEnumException] -> ShowS
Show)

instance Exception CEnumException where
  displayException :: CEnumException -> String
displayException = \case
    CEnumNotDeclared Integer
i -> String
"C enumeration value not declared: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
Prelude.show Integer
i
    CEnumNoSuccessor Integer
i ->
      String
"C enumeration value has no declared successor: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
Prelude.show Integer
i
    CEnumNoPredecessor Integer
i ->
      String
"C enumeration value has no declared predecessor: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
Prelude.show Integer
i
    CEnumException
CEnumEmpty -> String
"C enumeration has no declared values"
    CEnumFromEqThen Integer
i -> String
"enumeration from and then values equal: " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Integer -> String
forall a. Show a => a -> String
Prelude.show Integer
i

{-------------------------------------------------------------------------------
  Bounded instance implementation
-------------------------------------------------------------------------------}

minBoundGen :: forall a. CEnum a => a
minBoundGen :: forall a. CEnum a => a
minBoundGen = case Map (CEnumZ a) (NonEmpty String)
-> Maybe (CEnumZ a, NonEmpty String)
forall k a. Map k a -> Maybe (k, a)
Map.lookupMin (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a)) of
    Just (CEnumZ a
i, NonEmpty String
_names) -> CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
i
    Maybe (CEnumZ a, NonEmpty String)
Nothing -> CEnumException -> a
forall a e. Exception e => e -> a
throw CEnumException
CEnumEmpty

minBoundSeq :: SequentialCEnum a => a
minBoundSeq :: forall a. SequentialCEnum a => a
minBoundSeq = a
forall a. SequentialCEnum a => a
minDeclaredValue

maxBoundGen :: forall a. CEnum a => a
maxBoundGen :: forall a. CEnum a => a
maxBoundGen = case Map (CEnumZ a) (NonEmpty String)
-> Maybe (CEnumZ a, NonEmpty String)
forall k a. Map k a -> Maybe (k, a)
Map.lookupMax (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a)) of
    Just (CEnumZ a
k, NonEmpty String
_names) -> CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
k
    Maybe (CEnumZ a, NonEmpty String)
Nothing -> CEnumException -> a
forall a e. Exception e => e -> a
throw CEnumException
CEnumEmpty

maxBoundSeq :: SequentialCEnum a => a
maxBoundSeq :: forall a. SequentialCEnum a => a
maxBoundSeq = a
forall a. SequentialCEnum a => a
maxDeclaredValue

{-------------------------------------------------------------------------------
  Enum instance implementation
-------------------------------------------------------------------------------}

succGen :: forall a. CEnum a => a -> a
succGen :: forall a. CEnum a => a -> a
succGen a
x = (Integer -> a) -> (a -> a) -> Either Integer a -> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a)
-> (Integer -> CEnumException) -> Integer -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) a -> a
forall a. a -> a
id (Either Integer a -> a) -> Either Integer a -> a
forall a b. (a -> b) -> a -> b
$ do
    (Map (CEnumZ a) (NonEmpty String)
_ltMap, Map (CEnumZ a) (NonEmpty String)
gtMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
    case Map (CEnumZ a) (NonEmpty String)
-> Maybe (CEnumZ a, NonEmpty String)
forall k a. Map k a -> Maybe (k, a)
Map.lookupMin Map (CEnumZ a) (NonEmpty String)
gtMap of
      Just (CEnumZ a
j, NonEmpty String
_names) -> a -> Either Integer a
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Either Integer a) -> a -> Either Integer a
forall a b. (a -> b) -> a -> b
$ CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
j
      Maybe (CEnumZ a, NonEmpty String)
Nothing -> CEnumException -> Either Integer a
forall a e. Exception e => e -> a
throw (CEnumException -> Either Integer a)
-> CEnumException -> Either Integer a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNoSuccessor (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    i :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

succSeq :: forall a. SequentialCEnum a => a -> a
succSeq :: forall a. SequentialCEnum a => a -> a
succSeq a
x
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
>= CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
maxZ = CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a
i CEnumZ a -> CEnumZ a -> CEnumZ a
forall a. Num a => a -> a -> a
+ CEnumZ a
1)
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Eq a => a -> a -> Bool
== CEnumZ a
maxZ = CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a) -> CEnumException -> a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNoSuccessor (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
    | Bool
otherwise = CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a) -> CEnumException -> a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    minZ, maxZ, i :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

predGen :: forall a. CEnum a => a -> a
predGen :: forall a. CEnum a => a -> a
predGen a
y = (Integer -> a) -> (a -> a) -> Either Integer a -> a
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a)
-> (Integer -> CEnumException) -> Integer -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) a -> a
forall a. a -> a
id (Either Integer a -> a) -> Either Integer a -> a
forall a b. (a -> b) -> a -> b
$ do
    (Map (CEnumZ a) (NonEmpty String)
ltMap, Map (CEnumZ a) (NonEmpty String)
_gtMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
j (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
    case Map (CEnumZ a) (NonEmpty String)
-> Maybe (CEnumZ a, NonEmpty String)
forall k a. Map k a -> Maybe (k, a)
Map.lookupMax Map (CEnumZ a) (NonEmpty String)
ltMap of
      Just (CEnumZ a
i, NonEmpty String
_names) -> a -> Either Integer a
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return (a -> Either Integer a) -> a -> Either Integer a
forall a b. (a -> b) -> a -> b
$ CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
i
      Maybe (CEnumZ a, NonEmpty String)
Nothing -> CEnumException -> Either Integer a
forall a e. Exception e => e -> a
throw (CEnumException -> Either Integer a)
-> CEnumException -> Either Integer a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNoPredecessor (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
j)
  where
    j :: CEnumZ a
    j :: CEnumZ a
j = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
y

predSeq :: forall a. SequentialCEnum a => a -> a
predSeq :: forall a. SequentialCEnum a => a -> a
predSeq a
y
    | CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
<= CEnumZ a
maxZ = CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a
j CEnumZ a -> CEnumZ a -> CEnumZ a
forall a. Num a => a -> a -> a
- CEnumZ a
1)
    | CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Eq a => a -> a -> Bool
== CEnumZ a
minZ = CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a) -> CEnumException -> a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNoPredecessor (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
j)
    | Bool
otherwise = CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a) -> CEnumException -> a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
j)
  where
    minZ, maxZ, j :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    j :: CEnumZ a
j    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
y

toEnumGen :: CEnum a => Int -> a
toEnumGen :: forall a. CEnum a => Int -> a
toEnumGen Int
i = case CEnumZ a -> Maybe a
forall a. CEnum a => CEnumZ a -> Maybe a
mkDeclared (Int -> CEnumZ a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i) of
    Just a
x  -> a
x
    Maybe a
Nothing -> CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a) -> CEnumException -> a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (Int -> Integer
forall a. Integral a => a -> Integer
toInteger Int
i)

toEnumSeq :: forall a. SequentialCEnum a => Int -> a
toEnumSeq :: forall a. SequentialCEnum a => Int -> a
toEnumSeq Int
n
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
>= CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
<= CEnumZ a
maxZ = CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum CEnumZ a
i
    | Bool
otherwise = CEnumException -> a
forall a e. Exception e => e -> a
throw (CEnumException -> a) -> CEnumException -> a
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    minZ, maxZ, i :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = Int -> CEnumZ a
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
n

fromEnumGen :: forall a. CEnum a => a -> Int
fromEnumGen :: forall a. CEnum a => a -> Int
fromEnumGen a
x
    | CEnumZ a
i CEnumZ a -> Map (CEnumZ a) (NonEmpty String) -> Bool
forall k a. Ord k => k -> Map k a -> Bool
`Map.member` Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a) = CEnumZ a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CEnumZ a
i
    | Bool
otherwise = CEnumException -> Int
forall a e. Exception e => e -> a
throw (CEnumException -> Int) -> CEnumException -> Int
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    i :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

fromEnumSeq :: forall a. SequentialCEnum a => a -> Int
fromEnumSeq :: forall a. SequentialCEnum a => a -> Int
fromEnumSeq a
x
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
>= CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
<= CEnumZ a
maxZ = CEnumZ a -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CEnumZ a
i
    | Bool
otherwise = CEnumException -> Int
forall a e. Exception e => e -> a
throw (CEnumException -> Int) -> CEnumException -> Int
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    minZ, maxZ, i :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

enumFromGen :: forall a. CEnum a => a -> [a]
enumFromGen :: forall a. CEnum a => a -> [a]
enumFromGen a
x = (Integer -> [a]) -> ([a] -> [a]) -> Either Integer [a] -> [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a])
-> (Integer -> CEnumException) -> Integer -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) [a] -> [a]
forall a. a -> a
id (Either Integer [a] -> [a]) -> Either Integer [a] -> [a]
forall a b. (a -> b) -> a -> b
$ do
    (Map (CEnumZ a) (NonEmpty String)
_ltMap, Map (CEnumZ a) (NonEmpty String)
gtMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
    [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either Integer [a]) -> [a] -> Either Integer [a]
forall a b. (a -> b) -> a -> b
$ a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (Map (CEnumZ a) (NonEmpty String) -> [CEnumZ a]
forall k a. Map k a -> [k]
Map.keys Map (CEnumZ a) (NonEmpty String)
gtMap)
  where
    i :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

enumFromSeq :: forall a. SequentialCEnum a => a -> [a]
enumFromSeq :: forall a. SequentialCEnum a => a -> [a]
enumFromSeq a
x
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
>= CEnumZ a
minZ Bool -> Bool -> Bool
&& CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
<= CEnumZ a
maxZ = (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum [CEnumZ a
i .. CEnumZ a
maxZ]
    | Bool
otherwise = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    minZ, maxZ, i :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x

enumFromThenGen :: forall a. CEnum a => a -> a -> [a]
enumFromThenGen :: forall a. CEnum a => a -> a -> [a]
enumFromThenGen a
x a
y = case CEnumZ a -> CEnumZ a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare CEnumZ a
i CEnumZ a
j of
    Ordering
LT -> (Integer -> [a]) -> ([a] -> [a]) -> Either Integer [a] -> [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a])
-> (Integer -> CEnumException) -> Integer -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) [a] -> [a]
forall a. a -> a
id (Either Integer [a] -> [a]) -> Either Integer [a] -> [a]
forall a b. (a -> b) -> a -> b
$ do
      (Map (CEnumZ a) (NonEmpty String)
_ltIMap, Map (CEnumZ a) (NonEmpty String)
gtIMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
      (Map (CEnumZ a) (NonEmpty String)
ltJMap,  Map (CEnumZ a) (NonEmpty String)
gtJMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
j Map (CEnumZ a) (NonEmpty String)
gtIMap
      let w :: Int
w  = Map (CEnumZ a) (NonEmpty String) -> Int
forall k a. Map k a -> Int
Map.size Map (CEnumZ a) (NonEmpty String)
ltJMap Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
          js :: [CEnumZ a]
js = CEnumZ a
j CEnumZ a -> [CEnumZ a] -> [CEnumZ a]
forall a. a -> [a] -> [a]
: Map (CEnumZ a) (NonEmpty String) -> [CEnumZ a]
forall k a. Map k a -> [k]
Map.keys Map (CEnumZ a) (NonEmpty String)
gtJMap
      [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either Integer [a]) -> [a] -> Either Integer [a]
forall a b. (a -> b) -> a -> b
$ a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (NonEmpty (CEnumZ a) -> a) -> [NonEmpty (CEnumZ a)] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a -> a)
-> (NonEmpty (CEnumZ a) -> CEnumZ a) -> NonEmpty (CEnumZ a) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (CEnumZ a) -> CEnumZ a
forall a. NonEmpty a -> a
NonEmpty.head) (Int -> [CEnumZ a] -> [NonEmpty (CEnumZ a)]
forall a. Int -> [a] -> [NonEmpty a]
nonEmptyChunksOf Int
w [CEnumZ a]
js)
    Ordering
GT -> (Integer -> [a]) -> ([a] -> [a]) -> Either Integer [a] -> [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a])
-> (Integer -> CEnumException) -> Integer -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) [a] -> [a]
forall a. a -> a
id (Either Integer [a] -> [a]) -> Either Integer [a] -> [a]
forall a b. (a -> b) -> a -> b
$ do
      (Map (CEnumZ a) (NonEmpty String)
ltIMap, Map (CEnumZ a) (NonEmpty String)
_gtIMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
      (Map (CEnumZ a) (NonEmpty String)
ltJMap, Map (CEnumZ a) (NonEmpty String)
gtJMap)  <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
j Map (CEnumZ a) (NonEmpty String)
ltIMap
      let w :: Int
w  = Map (CEnumZ a) (NonEmpty String) -> Int
forall k a. Map k a -> Int
Map.size Map (CEnumZ a) (NonEmpty String)
gtJMap Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
          js :: [CEnumZ a]
js = CEnumZ a
j CEnumZ a -> [CEnumZ a] -> [CEnumZ a]
forall a. a -> [a] -> [a]
: [CEnumZ a] -> [CEnumZ a]
forall a. [a] -> [a]
reverse (Map (CEnumZ a) (NonEmpty String) -> [CEnumZ a]
forall k a. Map k a -> [k]
Map.keys Map (CEnumZ a) (NonEmpty String)
ltJMap)
      [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either Integer [a]) -> [a] -> Either Integer [a]
forall a b. (a -> b) -> a -> b
$ a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (NonEmpty (CEnumZ a) -> a) -> [NonEmpty (CEnumZ a)] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a -> a)
-> (NonEmpty (CEnumZ a) -> CEnumZ a) -> NonEmpty (CEnumZ a) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (CEnumZ a) -> CEnumZ a
forall a. NonEmpty a -> a
NonEmpty.head) (Int -> [CEnumZ a] -> [NonEmpty (CEnumZ a)]
forall a. Int -> [a] -> [NonEmpty a]
nonEmptyChunksOf Int
w [CEnumZ a]
js)
    Ordering
EQ -> CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumFromEqThen (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    i, j :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x
    j :: CEnumZ a
j = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
y

enumFromThenSeq :: forall a. SequentialCEnum a => a -> a -> [a]
enumFromThenSeq :: forall a. SequentialCEnum a => a -> a -> [a]
enumFromThenSeq a
x a
y
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Eq a => a -> a -> Bool
== CEnumZ a
j = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumFromEqThen (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
    | CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
j)
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
j = (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum [CEnumZ a
i, CEnumZ a
j .. CEnumZ a
maxZ]
    | Bool
otherwise = (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum [CEnumZ a
i, CEnumZ a
j .. CEnumZ a
minZ]
  where
    minZ, maxZ, i, j :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x
    j :: CEnumZ a
j    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
y

enumFromToGen :: forall a. CEnum a => a -> a -> [a]
enumFromToGen :: forall a. CEnum a => a -> a -> [a]
enumFromToGen a
x a
z = (Integer -> [a]) -> ([a] -> [a]) -> Either Integer [a] -> [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a])
-> (Integer -> CEnumException) -> Integer -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) [a] -> [a]
forall a. a -> a
id (Either Integer [a] -> [a]) -> Either Integer [a] -> [a]
forall a b. (a -> b) -> a -> b
$ do
    (Map (CEnumZ a) (NonEmpty String)
_ltIMap, Map (CEnumZ a) (NonEmpty String)
gtIMap)  <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
    if CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Eq a => a -> a -> Bool
== CEnumZ a
k
      then [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return [a
x]
      else do
        (Map (CEnumZ a) (NonEmpty String)
ltKMap,  Map (CEnumZ a) (NonEmpty String)
_gtKMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
k Map (CEnumZ a) (NonEmpty String)
gtIMap
        [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either Integer [a]) -> [a] -> Either Integer [a]
forall a b. (a -> b) -> a -> b
$ a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (Map (CEnumZ a) (NonEmpty String) -> [CEnumZ a]
forall k a. Map k a -> [k]
Map.keys Map (CEnumZ a) (NonEmpty String)
ltKMap) [a] -> [a] -> [a]
forall a. [a] -> [a] -> [a]
++ [a
z]
  where
    i, k :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x
    k :: CEnumZ a
k = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
z

enumFromToSeq :: forall a. SequentialCEnum a => a -> a -> [a]
enumFromToSeq :: forall a. SequentialCEnum a => a -> a -> [a]
enumFromToSeq a
x a
z
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
    | CEnumZ a
k CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
k CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
k)
    | Bool
otherwise = (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum [CEnumZ a
i .. CEnumZ a
k]
  where
    minZ, maxZ, i, k :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x
    k :: CEnumZ a
k    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
z

enumFromThenToGen :: forall a. CEnum a => a -> a -> a -> [a]
enumFromThenToGen :: forall a. CEnum a => a -> a -> a -> [a]
enumFromThenToGen a
x a
y a
z = case CEnumZ a -> CEnumZ a -> Ordering
forall a. Ord a => a -> a -> Ordering
compare CEnumZ a
i CEnumZ a
j of
    Ordering
LT -> (Integer -> [a]) -> ([a] -> [a]) -> Either Integer [a] -> [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a])
-> (Integer -> CEnumException) -> Integer -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) [a] -> [a]
forall a. a -> a
id (Either Integer [a] -> [a]) -> Either Integer [a] -> [a]
forall a b. (a -> b) -> a -> b
$ do
      (Map (CEnumZ a) (NonEmpty String)
_ltIMap, Map (CEnumZ a) (NonEmpty String)
gtIMap)  <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
      (Map (CEnumZ a) (NonEmpty String)
ltJMap,  Map (CEnumZ a) (NonEmpty String)
gtJMap)  <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
j Map (CEnumZ a) (NonEmpty String)
gtIMap
      (Map (CEnumZ a) (NonEmpty String)
ltKMap,  Map (CEnumZ a) (NonEmpty String)
_gtKMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
k Map (CEnumZ a) (NonEmpty String)
gtJMap
      let w :: Int
w  = Map (CEnumZ a) (NonEmpty String) -> Int
forall k a. Map k a -> Int
Map.size Map (CEnumZ a) (NonEmpty String)
ltJMap Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
          js :: [CEnumZ a]
js = CEnumZ a
j CEnumZ a -> [CEnumZ a] -> [CEnumZ a]
forall a. a -> [a] -> [a]
: Map (CEnumZ a) (NonEmpty String) -> [CEnumZ a]
forall k a. Map k a -> [k]
Map.keys Map (CEnumZ a) (NonEmpty String)
ltKMap [CEnumZ a] -> [CEnumZ a] -> [CEnumZ a]
forall a. [a] -> [a] -> [a]
++ [CEnumZ a
k]
      [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either Integer [a]) -> [a] -> Either Integer [a]
forall a b. (a -> b) -> a -> b
$ a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (NonEmpty (CEnumZ a) -> a) -> [NonEmpty (CEnumZ a)] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a -> a)
-> (NonEmpty (CEnumZ a) -> CEnumZ a) -> NonEmpty (CEnumZ a) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (CEnumZ a) -> CEnumZ a
forall a. NonEmpty a -> a
NonEmpty.head) (Int -> [CEnumZ a] -> [NonEmpty (CEnumZ a)]
forall a. Int -> [a] -> [NonEmpty a]
nonEmptyChunksOf Int
w [CEnumZ a]
js)
    Ordering
GT -> (Integer -> [a]) -> ([a] -> [a]) -> Either Integer [a] -> [a]
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a])
-> (Integer -> CEnumException) -> Integer -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Integer -> CEnumException
CEnumNotDeclared) [a] -> [a]
forall a. a -> a
id (Either Integer [a] -> [a]) -> Either Integer [a] -> [a]
forall a b. (a -> b) -> a -> b
$ do
      (Map (CEnumZ a) (NonEmpty String)
ltIMap,  Map (CEnumZ a) (NonEmpty String)
_gtIMap) <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
i (Proxy a -> Map (CEnumZ a) (NonEmpty String)
forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues (Proxy a
forall {k} (t :: k). Proxy t
Proxy :: Proxy a))
      (Map (CEnumZ a) (NonEmpty String)
ltJMap,  Map (CEnumZ a) (NonEmpty String)
gtJMap)  <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
j Map (CEnumZ a) (NonEmpty String)
ltIMap
      (Map (CEnumZ a) (NonEmpty String)
_ltKMap, Map (CEnumZ a) (NonEmpty String)
gtKMap)  <- CEnumZ a
-> Map (CEnumZ a) (NonEmpty String)
-> Either
     Integer
     (Map (CEnumZ a) (NonEmpty String),
      Map (CEnumZ a) (NonEmpty String))
forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap CEnumZ a
k Map (CEnumZ a) (NonEmpty String)
ltJMap
      let w :: Int
w  = Map (CEnumZ a) (NonEmpty String) -> Int
forall k a. Map k a -> Int
Map.size Map (CEnumZ a) (NonEmpty String)
gtJMap Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
1
          js :: [CEnumZ a]
js = CEnumZ a
j CEnumZ a -> [CEnumZ a] -> [CEnumZ a]
forall a. a -> [a] -> [a]
: [CEnumZ a] -> [CEnumZ a]
forall a. [a] -> [a]
reverse (CEnumZ a
k CEnumZ a -> [CEnumZ a] -> [CEnumZ a]
forall a. a -> [a] -> [a]
: Map (CEnumZ a) (NonEmpty String) -> [CEnumZ a]
forall k a. Map k a -> [k]
Map.keys Map (CEnumZ a) (NonEmpty String)
gtKMap)
      [a] -> Either Integer [a]
forall a. a -> Either Integer a
forall (m :: * -> *) a. Monad m => a -> m a
return ([a] -> Either Integer [a]) -> [a] -> Either Integer [a]
forall a b. (a -> b) -> a -> b
$ a
x a -> [a] -> [a]
forall a. a -> [a] -> [a]
: (NonEmpty (CEnumZ a) -> a) -> [NonEmpty (CEnumZ a)] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map (CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum (CEnumZ a -> a)
-> (NonEmpty (CEnumZ a) -> CEnumZ a) -> NonEmpty (CEnumZ a) -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NonEmpty (CEnumZ a) -> CEnumZ a
forall a. NonEmpty a -> a
NonEmpty.head) (Int -> [CEnumZ a] -> [NonEmpty (CEnumZ a)]
forall a. Int -> [a] -> [NonEmpty a]
nonEmptyChunksOf Int
w [CEnumZ a]
js)
    Ordering
EQ -> CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumFromEqThen (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
  where
    i, j, k :: CEnumZ a
    i :: CEnumZ a
i = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x
    j :: CEnumZ a
j = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
y
    k :: CEnumZ a
k = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
z

enumFromThenToSeq :: forall a. SequentialCEnum a => a -> a -> a -> [a]
enumFromThenToSeq :: forall a. SequentialCEnum a => a -> a -> a -> [a]
enumFromThenToSeq a
x a
y a
z
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Eq a => a -> a -> Bool
== CEnumZ a
j = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumFromEqThen (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
    | CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
i CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
i)
    | CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
j CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
j)
    | CEnumZ a
k CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
< CEnumZ a
minZ Bool -> Bool -> Bool
|| CEnumZ a
k CEnumZ a -> CEnumZ a -> Bool
forall a. Ord a => a -> a -> Bool
> CEnumZ a
maxZ = CEnumException -> [a]
forall a e. Exception e => e -> a
throw (CEnumException -> [a]) -> CEnumException -> [a]
forall a b. (a -> b) -> a -> b
$ Integer -> CEnumException
CEnumNotDeclared (CEnumZ a -> Integer
forall a. Integral a => a -> Integer
toInteger CEnumZ a
k)
    | Bool
otherwise = (CEnumZ a -> a) -> [CEnumZ a] -> [a]
forall a b. (a -> b) -> [a] -> [b]
map CEnumZ a -> a
forall a. CEnum a => CEnumZ a -> a
toCEnum [CEnumZ a
i, CEnumZ a
j .. CEnumZ a
k]
  where
    minZ, maxZ, i, j, k :: CEnumZ a
    minZ :: CEnumZ a
minZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
minDeclaredValue @a)
    maxZ :: CEnumZ a
maxZ = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum (forall a. SequentialCEnum a => a
maxDeclaredValue @a)
    i :: CEnumZ a
i    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
x
    j :: CEnumZ a
j    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
y
    k :: CEnumZ a
k    = a -> CEnumZ a
forall a. CEnum a => a -> CEnumZ a
fromCEnum a
z

{-------------------------------------------------------------------------------
  Auxiliary Functions
-------------------------------------------------------------------------------}

getIntegralToDeclaredValues :: CEnum a => proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues :: forall a (proxy :: * -> *).
CEnum a =>
proxy a -> Map (CEnumZ a) (NonEmpty String)
getIntegralToDeclaredValues = DeclaredValues a -> Map (CEnumZ a) (NonEmpty String)
forall a. DeclaredValues a -> Map (CEnumZ a) (NonEmpty String)
integralToDeclaredValues (DeclaredValues a -> Map (CEnumZ a) (NonEmpty String))
-> (proxy a -> DeclaredValues a)
-> proxy a
-> Map (CEnumZ a) (NonEmpty String)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. proxy a -> DeclaredValues a
forall a (proxy :: * -> *). CEnum a => proxy a -> DeclaredValues a
forall (proxy :: * -> *). proxy a -> DeclaredValues a
declaredValues

nonEmptyChunksOf :: Int -> [a] -> [NonEmpty a]
nonEmptyChunksOf :: forall a. Int -> [a] -> [NonEmpty a]
nonEmptyChunksOf Int
n [a]
xs
    | Int
n Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
0     = [a] -> [NonEmpty a]
forall a. [a] -> [NonEmpty a]
aux [a]
xs
    | Bool
otherwise = String -> [NonEmpty a]
forall a. HasCallStack => String -> a
error (String -> [NonEmpty a]) -> String -> [NonEmpty a]
forall a b. (a -> b) -> a -> b
$ String
"nonEmptyChunksOf: n must be positive, got " String -> ShowS
forall a. [a] -> [a] -> [a]
++ Int -> String
forall a. Show a => a -> String
Prelude.show Int
n
  where
    aux :: [a] -> [NonEmpty a]
    aux :: forall a. [a] -> [NonEmpty a]
aux [a]
xs' = case ([a] -> Maybe (NonEmpty a))
-> ([a], [a]) -> (Maybe (NonEmpty a), [a])
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first [a] -> Maybe (NonEmpty a)
forall a. [a] -> Maybe (NonEmpty a)
NonEmpty.nonEmpty (Int -> [a] -> ([a], [a])
forall a. Int -> [a] -> ([a], [a])
List.splitAt Int
n [a]
xs') of
      (Just NonEmpty a
ne, [a]
rest)  -> NonEmpty a
ne NonEmpty a -> [NonEmpty a] -> [NonEmpty a]
forall a. a -> [a] -> [a]
: [a] -> [NonEmpty a]
forall a. [a] -> [NonEmpty a]
aux [a]
rest
      (Maybe (NonEmpty a)
Nothing, [a]
_rest) -> []

splitMap :: Integral k => k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap :: forall k v.
Integral k =>
k -> Map k v -> Either Integer (Map k v, Map k v)
splitMap k
n Map k v
m = case k -> Map k v -> (Map k v, Maybe v, Map k v)
forall k a. Ord k => k -> Map k a -> (Map k a, Maybe a, Map k a)
Map.splitLookup k
n Map k v
m of
    (Map k v
ltMap,  Just{},  Map k v
gtMap)  -> (Map k v, Map k v) -> Either Integer (Map k v, Map k v)
forall a b. b -> Either a b
Right (Map k v
ltMap, Map k v
gtMap)
    (Map k v
_ltMap, Maybe v
Nothing, Map k v
_gtMap) -> Integer -> Either Integer (Map k v, Map k v)
forall a b. a -> Either a b
Left (k -> Integer
forall a. Integral a => a -> Integer
toInteger k
n)