packages feed

plow-log-0.1.6.0: src/Plow/Logging/EnumerableConstructors.hs

{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}

module Plow.Logging.EnumerableConstructors (HasEnumerableConstructors (..)) where

import Data.Proxy
import GHC.Generics

class HasEnumerableConstructors1 f where
  listConstructors1 :: f p -> [String]
  allConstructors1 :: Proxy f -> [String]

instance HasEnumerableConstructors1 V1 where
  listConstructors1 _ = []
  allConstructors1 _ = []

instance HasEnumerableConstructors1 U1 where
  listConstructors1 _ = []
  allConstructors1 _ = []

instance (HasEnumerableConstructors a) => HasEnumerableConstructors1 (K1 i a) where
  listConstructors1 (K1 x) = listConstructors x
  allConstructors1 _ = allConstructors (Proxy :: Proxy a)

instance HasEnumerableConstructors1 f => HasEnumerableConstructors1 (D1 c f) where
  listConstructors1 (M1 x) = listConstructors1 x
  allConstructors1 _ = allConstructors1 (Proxy :: Proxy f)

instance (Constructor c, HasEnumerableConstructors1 f) => HasEnumerableConstructors1 (C1 c f) where
  listConstructors1 x@(M1 y) = [conName x] ++ listConstructors1 y
  allConstructors1 _ = [conName (undefined :: C1 c f g)] ++ allConstructors1 (Proxy :: Proxy f)

instance HasEnumerableConstructors1 f => HasEnumerableConstructors1 (S1 c f) where
  listConstructors1 (M1 x) = listConstructors1 x
  allConstructors1 _ = allConstructors1 (Proxy :: Proxy f)

instance (HasEnumerableConstructors1 a, HasEnumerableConstructors1 b) => HasEnumerableConstructors1 (a :+: b) where
  listConstructors1 (L1 x) = listConstructors1 x
  listConstructors1 (R1 x) = listConstructors1 x

  allConstructors1 _ = (allConstructors1 (Proxy :: Proxy a) ++ (allConstructors1 (Proxy :: Proxy b)))

instance (HasEnumerableConstructors1 a, HasEnumerableConstructors1 b) => HasEnumerableConstructors1 (a :*: b) where
  listConstructors1 (a :*: b) = listConstructors1 a ++ listConstructors1 b
  allConstructors1 _ = (allConstructors1 (Proxy :: Proxy a) ++ (allConstructors1 (Proxy :: Proxy b)))

instance HasEnumerableConstructors1 f => HasEnumerableConstructors1 (Rec1 f) where
  listConstructors1 (Rec1 a) = listConstructors1 a
  allConstructors1 _ = allConstructors1 (Proxy :: Proxy f)

class HasEnumerableConstructors a where
  listConstructors :: a -> [String]
  allConstructors :: Proxy a -> [String]
  default listConstructors :: (Generic a, HasEnumerableConstructors1 (Rep a)) => a -> [String]
  listConstructors = listConstructors1 . from

  default allConstructors :: (Generic a, HasEnumerableConstructors1 (Rep a)) => Proxy a -> [String]
  allConstructors _ = allConstructors1 (Proxy :: Proxy (Rep a))

instance {-# OVERLAPPABLE #-} HasEnumerableConstructors a where
  listConstructors _ = []
  allConstructors _ = []

instance HasEnumerableConstructors a => HasEnumerableConstructors [a] where
  listConstructors = concatMap listConstructors
  allConstructors _ = allConstructors (Proxy :: Proxy a)

instance HasEnumerableConstructors a => HasEnumerableConstructors (Maybe a) where
  listConstructors = maybe [] listConstructors
  allConstructors _ = allConstructors (Proxy :: Proxy a)

instance (HasEnumerableConstructors a, HasEnumerableConstructors b) => HasEnumerableConstructors (Either a b) where
  listConstructors = either listConstructors listConstructors
  allConstructors _ = allConstructors (Proxy :: Proxy a) ++ allConstructors (Proxy :: Proxy b)