    {-# LANGUAGE BangPatterns, TypeOperators, FlexibleContexts #-}

    -- |
    -- Module:  Control.DeepSeq.Generics
    -- Copyright:   (c) 2012, Herbert Valerio Riedel
    -- License:     BSD-style (see the LICENSE file)
    --
    -- Maintainer:  Herbert Valerio Riedel <hvr@gnu.org>
    -- Stability:   stable
    -- Portability: GHC
    --
    -- __NOTE__: Starting with @deepseq-1.4.0.0@, 'NFData' gained support
    -- for generic derivation via @DefaultSignatures@. The new default
    -- 'rnf' method implementation is then equivalent to
    --
    -- @
    -- instance NFData MyType where
    --   'rnf' = 'genericRnfV1'
    -- @
    --
    -- See documentation of 'rnf' for more details on how to use the new
    -- built-in 'Generic' support.

    module Control.DeepSeq.Generics
        ( genericRnf
        , genericRnfV1
        ) where

    import Control.DeepSeq
    import GHC.Generics

    -- | "GHC.Generics"-based 'rnf' implementation
    --
    -- This provides a generic `rnf` implementation for one type at a
    -- time. If the type of the value 'genericRnf' is asked to reduce to
    -- NF contains values of other types, those types have to provide
    -- 'NFData' instances. This also means that recursive types can only
    -- be used with 'genericRnf' if a 'NFData' instance has been defined
    -- as well (see examples below).
    --
    -- The typical usage for 'genericRnf' is for reducing boilerplate code
    -- when defining 'NFData' instances for ordinary algebraic
    -- datatypes. See the code below for some simple usage examples:
    --
    -- > {-# LANGUAGE DeriveGeneric #-}
    -- >
    -- > import Control.DeepSeq
    -- > import Control.DeepSeq.Generics (genericRnf)
    -- > import GHC.Generics
    -- >
    -- > -- simple record
    -- > data Foo = Foo AccountId Name Address
    -- >          deriving Generic
    -- >
    -- > type Address      = [String]
    -- > type Name         = String
    -- > newtype AccountId = AccountId Int
    -- >
    -- > instance NFData AccountId
    -- > instance NFData Foo where rnf = genericRnf
    -- >
    -- > -- recursive list-like type
    -- > data N = Z | S N deriving Generic
    -- >
    -- > instance NFData N where rnf = genericRnf
    -- >
    -- > -- parametric & recursive type
    -- > data Bar a = Bar0 | Bar1 a | Bar2 (Bar a)
    -- >            deriving Generic
    -- >
    -- > instance NFData a => NFData (Bar a) where rnf = genericRnf
    --
    -- __NOTE__: The 'GNFData' type-class showing up in the type-signature is
    --           used internally and not exported.

    genericRnf :: (Generic a, GNFData (Rep a)) => a -> ()
    genericRnf :: forall a. (Generic a, GNFData (Rep a)) => a -> ()
    genericRnf = Rep a (ZonkAny 1) -> ()
    forall a. Rep a a -> ()
    forall (f :: * -> *) a. GNFData f => f a -> ()
    grnf_ (Rep a (ZonkAny 1) -> ()) -> (a -> Rep a (ZonkAny 1)) -> a -> ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Rep a (ZonkAny 1)
    forall x. a -> Rep a x
    forall a x. Generic a => a -> Rep a x
    from
    {-# INLINE genericRnf #-}

    -- | Hidden internal type-class
    --
    -- __NOTE__: the 'V1' instance is not provided for 'GNFData' in order to
    -- trigger a compile-time error; see 'GNFDataV1' which defers this to
    -- a runtime error.
    class GNFData f where
        grnf_ :: f a -> ()

    instance GNFData U1 where
        grnf_ :: forall a. U1 a -> ()
    grnf_ U1 a
    U1 = ()

    instance NFData a => GNFData (K1 i a) where
        grnf_ :: forall a. K1 i a a -> ()
    grnf_ = a -> ()
    forall a. NFData a => a -> ()
    rnf (a -> ()) -> (K1 i a a -> a) -> K1 i a a -> ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . K1 i a a -> a
    forall k i c (p :: k). K1 i c p -> c
    unK1
        {-# INLINEABLE grnf_ #-}

    instance GNFData a => GNFData (M1 i c a) where
        grnf_ :: forall a. M1 i c a a -> ()
    grnf_ = a a -> ()
    forall a. a a -> ()
    forall (f :: * -> *) a. GNFData f => f a -> ()
    grnf_ (a a -> ()) -> (M1 i c a a -> a a) -> M1 i c a a -> ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . M1 i c a a -> a a
    forall k i (c :: Meta) (f :: k -> *) (p :: k). M1 i c f p -> f p
    unM1
        {-# INLINEABLE grnf_ #-}

    instance (GNFData a, GNFData b) => GNFData (a :*: b) where
        grnf_ :: forall a. (:*:) a b a -> ()
    grnf_ (a a
    x :*: b a
    y) = a a -> ()
    forall a. a a -> ()
    forall (f :: * -> *) a. GNFData f => f a -> ()
    grnf_ a a
    x () -> () -> ()
    forall a b. a -> b -> b
    `seq` b a -> ()
    forall a. b a -> ()
    forall (f :: * -> *) a. GNFData f => f a -> ()
    grnf_ b a
    y
        {-# INLINEABLE grnf_ #-}

    instance (GNFData a, GNFData b) => GNFData (a :+: b) where
        grnf_ :: forall a. (:+:) a b a -> ()
    grnf_ (L1 a a
    x) = a a -> ()
    forall a. a a -> ()
    forall (f :: * -> *) a. GNFData f => f a -> ()
    grnf_ a a
    x
        grnf_ (R1 b a
    x) = b a -> ()
    forall a. b a -> ()
    forall (f :: * -> *) a. GNFData f => f a -> ()
    grnf_ b a
    x
        {-# INLINEABLE grnf_ #-}

    -- | Variant of 'genericRnf' which supports derivation for uninhabited types.
    --
    -- For instance, the type
    --
    -- > data TagFoo deriving Generic
    --
    -- would cause a compile-time error with 'genericRnf', but with
    -- 'genericRnfV1' the error is deferred to run-time:
    --
    -- > Prelude> genericRnf (undefined :: TagFoo)
    -- >
    -- > <interactive>:1:1:
    -- >     No instance for (GNFData V1) arising from a use of `genericRnf'
    -- >     Possible fix: add an instance declaration for (GNFData V1)
    -- >     In the expression: genericRnf (undefined :: TagFoo)
    -- >     In an equation for `it': it = genericRnf (undefined :: TagFoo)
    -- >
    -- > Prelude> genericRnfV1 (undefined :: TagFoo)
    -- > *** Exception: Control.DeepSeq.Generics.genericRnfV1: uninhabited type
    --
    -- 'genericRnfV1' corresponds to @deepseq-1.4.0.0@'s default @rnf@
    -- method implementation.
    --
    -- __NOTE__: The 'GNFDataV1' type-class showing up in the type-signature is
    --           used internally and not exported.
    --
    -- @since 0.1.1.0
    genericRnfV1 :: (Generic a, GNFDataV1 (Rep a)) => a -> ()
    genericRnfV1 :: forall a. (Generic a, GNFDataV1 (Rep a)) => a -> ()
    genericRnfV1 = Rep a (ZonkAny 0) -> ()
    forall a. Rep a a -> ()
    forall (f :: * -> *) a. GNFDataV1 f => f a -> ()
    grnfV1_ (Rep a (ZonkAny 0) -> ()) -> (a -> Rep a (ZonkAny 0)) -> a -> ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> Rep a (ZonkAny 0)
    forall x. a -> Rep a x
    forall a x. Generic a => a -> Rep a x
    from
    {-# INLINE genericRnfV1 #-}

    -- | Variant of 'GNFData' supporting 'V1'
    class GNFDataV1 f where
        grnfV1_ :: f a -> ()

    instance GNFDataV1 V1 where
        grnfV1_ :: forall a. V1 a -> ()
    grnfV1_ = [Char] -> V1 a -> ()
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "Control.DeepSeq.Generics.genericRnfV1: uninhabited type"

    instance GNFDataV1 U1 where
        grnfV1_ :: forall a. U1 a -> ()
    grnfV1_ U1 a
    U1 = ()

    instance NFData a => GNFDataV1 (K1 i a) where
        grnfV1_ :: forall a. K1 i a a -> ()
    grnfV1_ = a -> ()
    forall a. NFData a => a -> ()
    rnf (a -> ()) -> (K1 i a a -> a) -> K1 i a a -> ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . K1 i a a -> a
    forall k i c (p :: k). K1 i c p -> c
    unK1
        {-# INLINEABLE grnfV1_ #-}

    instance GNFDataV1 a => GNFDataV1 (M1 i c a) where
        grnfV1_ :: forall a. M1 i c a a -> ()
    grnfV1_ = a a -> ()
    forall a. a a -> ()
    forall (f :: * -> *) a. GNFDataV1 f => f a -> ()
    grnfV1_ (a a -> ()) -> (M1 i c a a -> a a) -> M1 i c a a -> ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . M1 i c a a -> a a
    forall k i (c :: Meta) (f :: k -> *) (p :: k). M1 i c f p -> f p
    unM1
        {-# INLINEABLE grnfV1_ #-}

    instance (GNFDataV1 a, GNFDataV1 b) => GNFDataV1 (a :*: b) where
        grnfV1_ :: forall a. (:*:) a b a -> ()
    grnfV1_ (a a
    x :*: b a
    y) = a a -> ()
    forall a. a a -> ()
    forall (f :: * -> *) a. GNFDataV1 f => f a -> ()
    grnfV1_ a a
    x () -> () -> ()
    forall a b. a -> b -> b
    `seq` b a -> ()
    forall a. b a -> ()
    forall (f :: * -> *) a. GNFDataV1 f => f a -> ()
    grnfV1_ b a
    y
        {-# INLINEABLE grnfV1_ #-}

    instance (GNFDataV1 a, GNFDataV1 b) => GNFDataV1 (a :+: b) where
        grnfV1_ :: forall a. (:+:) a b a -> ()
    grnfV1_ (L1 a a
    x) = a a -> ()
    forall a. a a -> ()
    forall (f :: * -> *) a. GNFDataV1 f => f a -> ()
    grnfV1_ a a
    x
        grnfV1_ (R1 b a
    x) = b a -> ()
    forall a. b a -> ()
    forall (f :: * -> *) a. GNFDataV1 f => f a -> ()
    grnfV1_ b a
    x
        {-# INLINEABLE grnfV1_ #-}