{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeInType #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-unticked-promoted-constructors #-}
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
module Generics.SOP.Record
(
FieldLabel
, RecordCode
, Record
, RecordRep
, RecordCodeOf
, IsRecord
, ValidRecordCode
, ExtractTypesFromRecordCode
, ExtractLabelsFromRecordCode
, RecombineRecordCode
, toRecord
, fromRecord
, P(..)
, Snd
)
where
import Control.DeepSeq
import Generics.SOP.BasicFunctors
import Generics.SOP.NP
import Generics.SOP.NS
import Generics.SOP.Universe
import Generics.SOP.Sing
import Generics.SOP.Type.Metadata
import qualified GHC.Generics as GHC
import GHC.TypeLits
import GHC.Types
import Unsafe.Coerce
type FieldLabel = Symbol
type RecordCode = [(FieldLabel, Type)]
type RecordRep (a :: Type) = Record (RecordCodeOf a)
type Record (r :: RecordCode) = NP P r
type RecordCodeOf a = ToRecordCode_Datatype a (DatatypeInfoOf a) (Code a)
type family
ToRecordCode_Datatype (a :: Type) (d :: DatatypeInfo) (c :: [[Type]]) :: RecordCode where
#if MIN_VERSION_generics_sop(0,5,0)
ToRecordCode_Datatype a (ADT _ _ cis _) c = ToRecordCode_Constructor a cis c
#else
ToRecordCode_Datatype a (ADT _ _ cis) c = ToRecordCode_Constructor a cis c
#endif
ToRecordCode_Datatype a (Newtype _ _ ci) c = ToRecordCode_Constructor a '[ ci ] c
type family
ToRecordCode_Constructor (a :: Type) (cis :: [ConstructorInfo]) (c :: [[Type]]) :: RecordCode where
ToRecordCode_Constructor a '[ 'Record _ fis ] '[ ts ] = ToRecordCode_Field fis ts
ToRecordCode_Constructor a '[ 'Constructor _ ] '[ '[] ] = '[]
ToRecordCode_Constructor a '[] _ =
TypeError
( Text "The type `" :<>: ShowType a :<>: Text "' is not a record type."
:$$: Text "It has no constructors."
)
ToRecordCode_Constructor a ( _ : _ : _ ) _ =
TypeError
( Text "The type `" :<>: ShowType a :<>: Text "' is not a record type."
:$$: Text "It has more than one constructor."
)
ToRecordCode_Constructor a '[ _ ] _ =
TypeError
( Text "The type `" :<>: ShowType a :<>: Text "' is not a record type."
:$$: Text "It has no labelled fields."
)
type family ToRecordCode_Field (fis :: [FieldInfo]) (c :: [Type]) :: RecordCode where
ToRecordCode_Field '[] '[] = '[]
ToRecordCode_Field ( 'FieldInfo l : fis ) ( t : ts ) = '(l, t) : ToRecordCode_Field fis ts
type IsRecord (a :: Type) (r :: RecordCode) =
IsRecord' a r (GetSingleton (Code a))
type IsRecord' (a :: Type) (r :: RecordCode) (xs :: [Type]) =
( Generic a, Code a ~ '[ xs ]
, RecordCodeOf a ~ r, ValidRecordCode r xs
)
type ValidRecordCode (r :: RecordCode) (xs :: [Type]) =
( ExtractTypesFromRecordCode r ~ xs
, RecombineRecordCode (ExtractLabelsFromRecordCode r) xs ~ r
)
type family (r :: RecordCode) :: [Type] where
'[] = '[]
( '(_, a) : r ) = a : ExtractTypesFromRecordCode r
type family (r :: RecordCode) :: [FieldLabel] where
'[] = '[]
( '(l, _) : r ) = l : ExtractLabelsFromRecordCode r
type family RecombineRecordCode (ls :: [FieldLabel]) (ts :: [Type]) :: RecordCode where
RecombineRecordCode _ '[] = '[]
RecombineRecordCode ls (t : ts) = '(Head ls, t) : RecombineRecordCode (Tail ls) ts
toRecord :: (IsRecord a _r) => a -> RecordRep a
toRecord :: a -> RecordRep a
toRecord = NP I (GetSingleton (Code a)) -> Record _r
forall (r :: RecordCode) (xs :: [*]).
ValidRecordCode r xs =>
NP I xs -> Record r
unsafeToRecord_NP (NP I (GetSingleton (Code a)) -> Record _r)
-> (a -> NP I (GetSingleton (Code a))) -> a -> Record _r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NS (NP I) '[GetSingleton (Code a)] -> NP I (GetSingleton (Code a))
forall k (f :: k -> *) (x :: k). NS f '[x] -> f x
unZ (NS (NP I) '[GetSingleton (Code a)]
-> NP I (GetSingleton (Code a)))
-> (a -> NS (NP I) '[GetSingleton (Code a)])
-> a
-> NP I (GetSingleton (Code a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SOP I '[GetSingleton (Code a)]
-> NS (NP I) '[GetSingleton (Code a)]
forall k (f :: k -> *) (xss :: [[k]]). SOP f xss -> NS (NP f) xss
unSOP (SOP I '[GetSingleton (Code a)]
-> NS (NP I) '[GetSingleton (Code a)])
-> (a -> SOP I '[GetSingleton (Code a)])
-> a
-> NS (NP I) '[GetSingleton (Code a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> SOP I '[GetSingleton (Code a)]
forall a. Generic a => a -> Rep a
from
_toRecord_NP :: (ValidRecordCode r xs) => NP I xs -> Record r
_toRecord_NP :: NP I xs -> Record r
_toRecord_NP NP I xs
Nil = Record r
forall k (a :: k -> *). NP a '[]
Nil
_toRecord_NP (I x
x :* NP I xs
xs) = Snd '(Head (ExtractLabelsFromRecordCode r), x)
-> P '(Head (ExtractLabelsFromRecordCode r), x)
forall a (p :: (a, *)). Snd p -> P p
P x
Snd '(Head (ExtractLabelsFromRecordCode r), x)
x P '(Head (ExtractLabelsFromRecordCode r), x)
-> NP
P (RecombineRecordCode (Tail (ExtractLabelsFromRecordCode r)) xs)
-> NP
P
('(Head (ExtractLabelsFromRecordCode r), x)
: RecombineRecordCode (Tail (ExtractLabelsFromRecordCode r)) xs)
forall k (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* NP I xs
-> NP
P (RecombineRecordCode (Tail (ExtractLabelsFromRecordCode r)) xs)
forall (r :: RecordCode) (xs :: [*]).
ValidRecordCode r xs =>
NP I xs -> Record r
_toRecord_NP NP I xs
xs
unsafeToRecord_NP :: (ValidRecordCode r xs) => NP I xs -> Record r
unsafeToRecord_NP :: NP I xs -> Record r
unsafeToRecord_NP = NP I xs -> Record r
forall a b. a -> b
unsafeCoerce
fromRecord :: (IsRecord a r) => RecordRep a -> a
fromRecord :: RecordRep a -> a
fromRecord = SOP I '[GetSingleton (Code a)] -> a
forall a. Generic a => Rep a -> a
to (SOP I '[GetSingleton (Code a)] -> a)
-> (Record r -> SOP I '[GetSingleton (Code a)]) -> Record r -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NS (NP I) '[GetSingleton (Code a)]
-> SOP I '[GetSingleton (Code a)]
forall k (f :: k -> *) (xss :: [[k]]). NS (NP f) xss -> SOP f xss
SOP (NS (NP I) '[GetSingleton (Code a)]
-> SOP I '[GetSingleton (Code a)])
-> (Record r -> NS (NP I) '[GetSingleton (Code a)])
-> Record r
-> SOP I '[GetSingleton (Code a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. NP I (GetSingleton (Code a)) -> NS (NP I) '[GetSingleton (Code a)]
forall k (a :: k -> *) (x :: k) (xs :: [k]). a x -> NS a (x : xs)
Z (NP I (GetSingleton (Code a))
-> NS (NP I) '[GetSingleton (Code a)])
-> (Record r -> NP I (GetSingleton (Code a)))
-> Record r
-> NS (NP I) '[GetSingleton (Code a)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Record r -> NP I (GetSingleton (Code a))
forall (r :: RecordCode) (xs :: [*]).
(ValidRecordCode r xs, SListI xs) =>
Record r -> NP I xs
unsafeFromRecord_NP
_fromRecord_NP :: forall r xs . (ValidRecordCode r xs, SListI xs) => Record r -> NP I xs
_fromRecord_NP :: Record r -> NP I xs
_fromRecord_NP = case SList xs
forall k (xs :: [k]). SListI xs => SList xs
sList :: SList xs of
SList xs
SNil -> NP I '[] -> Record r -> NP I '[]
forall a b. a -> b -> a
const NP I '[]
forall k (a :: k -> *). NP a '[]
Nil
SList xs
SCons -> \ Record r
r -> case Record r
r of
P Snd x
x :* NP P xs
xs -> x -> I x
forall a. a -> I a
I x
Snd x
x I x -> NP I xs -> NP I (x : xs)
forall k (a :: k -> *) (x :: k) (xs :: [k]).
a x -> NP a xs -> NP a (x : xs)
:* NP P xs -> NP I xs
forall (r :: RecordCode) (xs :: [*]).
(ValidRecordCode r xs, SListI xs) =>
Record r -> NP I xs
_fromRecord_NP NP P xs
xs
unsafeFromRecord_NP :: forall r xs . (ValidRecordCode r xs, SListI xs) => Record r -> NP I xs
unsafeFromRecord_NP :: Record r -> NP I xs
unsafeFromRecord_NP = Record r -> NP I xs
forall a b. a -> b
unsafeCoerce
newtype P (p :: (a, Type)) = P (Snd p)
deriving ((forall x. P p -> Rep (P p) x)
-> (forall x. Rep (P p) x -> P p) -> Generic (P p)
forall x. Rep (P p) x -> P p
forall x. P p -> Rep (P p) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a (p :: (a, *)) x. Rep (P p) x -> P p
forall a (p :: (a, *)) x. P p -> Rep (P p) x
$cto :: forall a (p :: (a, *)) x. Rep (P p) x -> P p
$cfrom :: forall a (p :: (a, *)) x. P p -> Rep (P p) x
GHC.Generic)
deriving instance Eq a => Eq (P '(l, a))
deriving instance Ord a => Ord (P '(l, a))
deriving instance Show a => Show (P '(l, a))
instance NFData a => NFData (P '(l, a)) where
rnf :: P '(l, a) -> ()
rnf (P Snd '(l, a)
x) = a -> ()
forall a. NFData a => a -> ()
rnf a
Snd '(l, a)
x
type family Snd (p :: (a, b)) :: b where
Snd '(a, b) = b
type family Head (xs :: [k]) :: k where
Head (x : xs) = x
type family Tail (xs :: [k]) :: [k] where
Tail (x : xs) = xs
type family GetSingleton (xs :: [k]) :: k where
GetSingleton '[ x ] = x