{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeOperators #-}

-- | Function for getting the names of fields in a type
--
-- <https://stackoverflow.com/questions/27815489/is-it-possible-to-list-the-names-and-types-of-fields-in-a-record-data-type-that>
--
module GHC.Generics.Selectors
    ( Selectors(..)
    )
where

import Prelude

import Data.Proxy
import GHC.Generics

class Selectors rep where
  selectors :: Proxy rep -> [String]

instance Selectors f => Selectors (M1 D x f) where
    selectors :: Proxy (M1 D x f) -> [String]
selectors _ = Proxy f -> [String]
forall k (rep :: k). Selectors rep => Proxy rep -> [String]
selectors (Proxy f
forall k (t :: k). Proxy t
Proxy :: Proxy f)

instance Selectors f => Selectors (M1 C x f) where
    selectors :: Proxy (M1 C x f) -> [String]
selectors _ = Proxy f -> [String]
forall k (rep :: k). Selectors rep => Proxy rep -> [String]
selectors (Proxy f
forall k (t :: k). Proxy t
Proxy :: Proxy f)

instance Selector s => Selectors (M1 S s (K1 R t)) where
    selectors :: Proxy (M1 S s (K1 R t)) -> [String]
selectors _ = [M1 S s (K1 R t) () -> String
forall k (s :: k) k1 (t :: k -> (k1 -> *) -> k1 -> *)
       (f :: k1 -> *) (a :: k1).
Selector s =>
t s f a -> String
selName (M1 S s (K1 R t) ()
forall a. HasCallStack => a
undefined :: M1 S s (K1 R t) ())]

instance (Selectors a, Selectors b) => Selectors (a :*: b) where
    selectors :: Proxy (a :*: b) -> [String]
selectors _ = Proxy a -> [String]
forall k (rep :: k). Selectors rep => Proxy rep -> [String]
selectors (Proxy a
forall k (t :: k). Proxy t
Proxy :: Proxy a) [String] -> [String] -> [String]
forall a. [a] -> [a] -> [a]
++ Proxy b -> [String]
forall k (rep :: k). Selectors rep => Proxy rep -> [String]
selectors (Proxy b
forall k (t :: k). Proxy t
Proxy :: Proxy b)

instance Selectors U1 where
    selectors :: Proxy U1 -> [String]
selectors _ = []