{-# LANGUAGE UndecidableInstances #-}
module Wakame.Row
  ( FIELD

  -- * Keyed value type and function
  , V (..)
  , Keyed
  , keyed

  -- * Row type
  , Row
  , IsRow (..)

  -- * Re-export from Data.SOP.NP
  , NP (..)
  ) where

import Prelude

import Data.Kind
import Data.Proxy
import Data.SOP.NP (NP (..))
import GHC.Generics
import GHC.TypeLits
import Wakame.Utils (Fst, Snd)


-- | Kind of field
type FIELD = (Symbol, Type)


-- |
-- >>> V 3 :: V '("x", Int)
-- (x: 3)
newtype V (p :: FIELD) = V { unV :: Snd p }

instance (KnownSymbol (Fst p), Show (Snd p)) => Show (V p) where
  show (V x) = "(" <> symbolVal (Proxy @(Fst p)) <> ": " <> show x <> ")"

instance (KnownSymbol (Fst p), Eq (Snd p)) => Eq (V p) where
  (==) (V x) (V y) = x == y

instance Generic (V '(k, v)) where
  type Rep (V '(k, v)) = S1 ('MetaSel ('Just k) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 v)
  from (V x) = M1 (K1 x)
  to (M1 (K1 x)) = V x

-- * Helper functions

type Keyed k v = V '(k, v)

keyed :: KnownSymbol k => v -> Keyed k v
keyed = V

-- * Row type

type Row as = NP V (as :: [FIELD])

-- | Typeclass of converting from/to @Row@
class IsRow (a :: Type) where
  type Of a :: [FIELD]
  fromRow :: Row (Of a) -> a
  toRow :: a -> Row (Of a)