{-# LANGUAGE UndecidableInstances #-}
module Wakame.Keys where

import Prelude

import Data.Proxy
import Data.String (IsString (..))
import GHC.Generics
import GHC.TypeLits
import Wakame.Row (V (..))


-- $setup
-- >>> import Wakame
-- >>> data Point = Point { x :: Double, y :: Double } deriving (Show, Generic)
-- >>> pt = Point 1.2 8.3


-- | Function to retrieve key values
--
-- Return value can be anything which has @IsString@ instance.
-- >>> import Data.Functor.Identity (Identity)
-- >>> keys pt :: [Identity String]
-- [Identity "x",Identity "y"]
keys :: (IsString s, Generic a, Keys' s (Rep a)) => a -> [s]
keys = keys' . from


class IsString s => Keys' s f where
  keys' :: f a -> [s]

instance Keys' s a => Keys' s (D1 f a) where
  keys' (M1 x) = keys' x

instance Keys' s a => Keys' s (C1 f a) where
  keys' (M1 x) = keys' x

instance (Keys' s a, Keys' s b) => Keys' s (a :*: b) where
  keys' (x :*: y) = keys' x <> keys' y

instance (IsString s, KnownSymbol key) => Keys' s (S1 ('MetaSel ('Just key) su ss ds) a) where
  keys' _ = [fromString $ symbolVal (Proxy @key)]

instance (IsString s, KnownSymbol key) => Keys' s (S1 ('MetaSel 'Nothing su ss ds) (Rec0 (V '(key, a)))) where
  keys' _ = [fromString $ symbolVal (Proxy @key)]