{-# LANGUAGE
    AllowAmbiguousTypes
  , FlexibleInstances
  , MultiParamTypeClasses
  , ScopedTypeVariables
  , TypeApplications
  , TypeInType
  , TypeFamilies
  , TypeOperators
  , UndecidableInstances
#-}
{-# OPTIONS_GHC
  -fno-warn-unticked-promoted-constructors
#-}
module Generics.SOP.Record.SubTyping
  ( cast
  , IsSubTypeOf
  , IsElemOf
  )
  where
import Data.Type.Equality
import Generics.SOP.NP
import GHC.Types
import Generics.SOP.Record
cast :: (IsRecord a ra, IsRecord b rb, IsSubTypeOf ra rb) => a -> b
cast = fromRecord . castRecord . toRecord
class IsSubTypeOf (r1 :: RecordCode) (r2 :: RecordCode) where
  
  castRecord :: Record r1 -> Record r2
instance IsSubTypeOf r1 '[] where
  castRecord _ = Nil
instance (IsSubTypeOf r1 r2, IsElemOf s2 a2 r1) => IsSubTypeOf r1 ( '(s2, a2) : r2 ) where
  castRecord r = P (get @s2 r) :* castRecord r
class IsElemOf (s :: Symbol) (a :: Type) (r :: RecordCode) where
  
  
  
  get :: Record r -> a
class IsElemOf' (b :: Bool)
  (s1 :: FieldLabel) (a1 :: Type)
  (s2 :: FieldLabel) (a2 :: Type)
  (r :: RecordCode)
  where
  get' :: Record ( '(s2, a2) : r ) -> a1
instance
  IsElemOf' (SameFieldLabel s1 s2) s1 a1 s2 a2 r =>
  IsElemOf s1 a1 ( '(s2, a2) : r )
  where
  get = get' @(SameFieldLabel s1 s2) @s1
instance (a1 ~ a2) => IsElemOf' True s a1 s a2 r where
  get' (P a :* _) = a
instance IsElemOf s1 a1 r => IsElemOf' False s1 a1 s2 a2 r where
  get' (_ :* r) = get @s1 r
type family
  SameFieldLabel (s1 :: FieldLabel) (s2 :: FieldLabel) :: Bool where
  SameFieldLabel s1 s2 = s1 == s2