{-# language DataKinds #-}
{-# language FlexibleInstances #-}
{-# language PolyKinds #-}
{-# language ScopedTypeVariables #-}
{-# language TypeApplications #-}
{-# language TypeFamilies #-}
{-# language TypeOperators #-}
{-# language UndecidableInstances #-}
module Mu.Schema.Definition (
Schema', Schema, SchemaB
, TypeDef, TypeDefB(..)
, ChoiceDef(..)
, FieldDef, FieldDefB(..)
, FieldType, FieldTypeB(..)
, (:/:)
, Mapping(..), Mappings
, MappingRight, MappingLeft
, reflectSchema
, reflectFields, reflectChoices
, reflectFieldTypes, reflectFieldType
, KnownName(..)
) where
import Data.Kind
import Data.Proxy
import Data.Typeable
import GHC.TypeLits
type Schema' = Schema Symbol Symbol
class KnownName (a :: k) where
nameVal :: proxy a -> String
instance KnownSymbol s => KnownName (s :: Symbol) where
nameVal :: proxy s -> String
nameVal = proxy s -> String
forall (n :: Symbol) (proxy :: Symbol -> *).
KnownSymbol n =>
proxy n -> String
symbolVal
instance KnownName 'True where
nameVal :: proxy 'True -> String
nameVal _ = "True"
instance KnownName 'False where
nameVal :: proxy 'False -> String
nameVal _ = "False"
instance KnownNat n => KnownName (n :: Nat) where
nameVal :: proxy n -> String
nameVal = Integer -> String
forall a. Show a => a -> String
show (Integer -> String) -> (proxy n -> Integer) -> proxy n -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. proxy n -> Integer
forall (n :: Nat) (proxy :: Nat -> *).
KnownNat n =>
proxy n -> Integer
natVal
type Schema typeName fieldName
= SchemaB Type typeName fieldName
type SchemaB builtin typeName fieldName
= [TypeDefB builtin typeName fieldName]
type TypeDef = TypeDefB Type
data TypeDefB builtin typeName fieldName
=
DRecord typeName [FieldDefB builtin typeName fieldName]
| DEnum typeName [ChoiceDef fieldName]
| DSimple (FieldTypeB builtin typeName)
newtype ChoiceDef fieldName
=
ChoiceDef fieldName
type FieldDef = FieldDefB Type
data FieldDefB builtin typeName fieldName
=
FieldDef fieldName (FieldTypeB builtin typeName)
type FieldType = FieldTypeB Type
data FieldTypeB builtin typeName
=
TNull
| TPrimitive builtin
| TSchematic typeName
| TOption (FieldTypeB builtin typeName)
| TList (FieldTypeB builtin typeName)
| TMap (FieldTypeB builtin typeName) (FieldTypeB builtin typeName)
| TUnion [FieldTypeB builtin typeName]
instance KnownName n => KnownName ('DRecord n fields) where
nameVal :: proxy ('DRecord n fields) -> String
nameVal _ = Proxy n -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy n
forall k (t :: k). Proxy t
Proxy @n)
instance KnownName n => KnownName ('DEnum n choices) where
nameVal :: proxy ('DEnum n choices) -> String
nameVal _ = Proxy n -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy n
forall k (t :: k). Proxy t
Proxy @n)
instance KnownName n => KnownName ('ChoiceDef n) where
nameVal :: proxy ('ChoiceDef n) -> String
nameVal _ = Proxy n -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy n
forall k (t :: k). Proxy t
Proxy @n)
instance KnownName n => KnownName ('FieldDef n t) where
nameVal :: proxy ('FieldDef n t) -> String
nameVal _ = Proxy n -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy n
forall k (t :: k). Proxy t
Proxy @n)
type family (sch :: Schema t f) :/: (name :: t) :: TypeDef t f where
'[] :/: name = TypeError ('Text "Cannot find type " ':<>: 'ShowType name ':<>: 'Text " in the schema")
('DRecord name fields ': rest) :/: name = 'DRecord name fields
('DEnum name choices ': rest) :/: name = 'DEnum name choices
(other ': rest) :/: name = rest :/: name
data Mapping a b = a :-> b
type Mappings a b = [Mapping a b]
type family MappingRight (ms :: Mappings a b) (v :: a) :: b where
MappingRight '[] (v :: Symbol) = v
MappingRight '[] v = TypeError ('Text "Cannot find value " ':<>: 'ShowType v)
MappingRight ((x ':-> y) ': rest) x = y
MappingRight (other ': rest) x = MappingRight rest x
type family MappingLeft (ms :: Mappings a b) (v :: b) :: a where
MappingLeft '[] (v :: Symbol) = v
MappingLeft '[] v = TypeError ('Text "Cannot find value " ':<>: 'ShowType v)
MappingLeft ((x ':-> y) ': rest) y = x
MappingLeft (other ': rest) y = MappingLeft rest y
class ReflectSchema (s :: Schema tn fn) where
reflectSchema :: Proxy s -> SchemaB TypeRep String String
instance ReflectSchema '[] where
reflectSchema :: Proxy '[] -> SchemaB TypeRep String String
reflectSchema _ = []
instance (ReflectFields fields, KnownName name, ReflectSchema s)
=> ReflectSchema ('DRecord name fields ': s) where
reflectSchema :: Proxy ('DRecord name fields : s) -> SchemaB TypeRep String String
reflectSchema _ = String
-> [FieldDefB TypeRep String String]
-> TypeDefB TypeRep String String
forall builtin typeName fieldName.
typeName
-> [FieldDefB builtin typeName fieldName]
-> TypeDefB builtin typeName fieldName
DRecord (Proxy name -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy name
forall k (t :: k). Proxy t
Proxy @name)) (Proxy fields -> [FieldDefB TypeRep String String]
forall tn fn (fs :: [FieldDef tn fn]).
ReflectFields fs =>
Proxy fs -> [FieldDefB TypeRep String String]
reflectFields (Proxy fields
forall k (t :: k). Proxy t
Proxy @fields))
TypeDefB TypeRep String String
-> SchemaB TypeRep String String -> SchemaB TypeRep String String
forall a. a -> [a] -> [a]
: Proxy s -> SchemaB TypeRep String String
forall tn fn (s :: Schema tn fn).
ReflectSchema s =>
Proxy s -> SchemaB TypeRep String String
reflectSchema (Proxy s
forall k (t :: k). Proxy t
Proxy @s)
instance (ReflectChoices choices, KnownName name, ReflectSchema s)
=> ReflectSchema ('DEnum name choices ': s) where
reflectSchema :: Proxy ('DEnum name choices : s) -> SchemaB TypeRep String String
reflectSchema _ = String -> [ChoiceDef String] -> TypeDefB TypeRep String String
forall builtin typeName fieldName.
typeName
-> [ChoiceDef fieldName] -> TypeDefB builtin typeName fieldName
DEnum (Proxy name -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy name
forall k (t :: k). Proxy t
Proxy @name)) (Proxy choices -> [ChoiceDef String]
forall fn (cs :: [ChoiceDef fn]).
ReflectChoices cs =>
Proxy cs -> [ChoiceDef String]
reflectChoices (Proxy choices
forall k (t :: k). Proxy t
Proxy @choices))
TypeDefB TypeRep String String
-> SchemaB TypeRep String String -> SchemaB TypeRep String String
forall a. a -> [a] -> [a]
: Proxy s -> SchemaB TypeRep String String
forall tn fn (s :: Schema tn fn).
ReflectSchema s =>
Proxy s -> SchemaB TypeRep String String
reflectSchema (Proxy s
forall k (t :: k). Proxy t
Proxy @s)
instance (ReflectFieldType ty, ReflectSchema s)
=> ReflectSchema ('DSimple ty ': s) where
reflectSchema :: Proxy ('DSimple ty : s) -> SchemaB TypeRep String String
reflectSchema _ = FieldTypeB TypeRep String -> TypeDefB TypeRep String String
forall builtin typeName fieldName.
FieldTypeB builtin typeName -> TypeDefB builtin typeName fieldName
DSimple (Proxy ty -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy ty
forall k (t :: k). Proxy t
Proxy @ty))
TypeDefB TypeRep String String
-> SchemaB TypeRep String String -> SchemaB TypeRep String String
forall a. a -> [a] -> [a]
: Proxy s -> SchemaB TypeRep String String
forall tn fn (s :: Schema tn fn).
ReflectSchema s =>
Proxy s -> SchemaB TypeRep String String
reflectSchema (Proxy s
forall k (t :: k). Proxy t
Proxy @s)
class ReflectFields (fs :: [FieldDef tn fn]) where
reflectFields :: Proxy fs -> [FieldDefB TypeRep String String]
instance ReflectFields '[] where
reflectFields :: Proxy '[] -> [FieldDefB TypeRep String String]
reflectFields _ = []
instance (KnownName name, ReflectFieldType ty, ReflectFields fs)
=> ReflectFields ('FieldDef name ty ': fs) where
reflectFields :: Proxy ('FieldDef name ty : fs) -> [FieldDefB TypeRep String String]
reflectFields _ = String
-> FieldTypeB TypeRep String -> FieldDefB TypeRep String String
forall builtin typeName fieldName.
fieldName
-> FieldTypeB builtin typeName
-> FieldDefB builtin typeName fieldName
FieldDef (Proxy name -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy name
forall k (t :: k). Proxy t
Proxy @name)) (Proxy ty -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy ty
forall k (t :: k). Proxy t
Proxy @ty))
FieldDefB TypeRep String String
-> [FieldDefB TypeRep String String]
-> [FieldDefB TypeRep String String]
forall a. a -> [a] -> [a]
: Proxy fs -> [FieldDefB TypeRep String String]
forall tn fn (fs :: [FieldDef tn fn]).
ReflectFields fs =>
Proxy fs -> [FieldDefB TypeRep String String]
reflectFields (Proxy fs
forall k (t :: k). Proxy t
Proxy @fs)
class ReflectChoices (cs :: [ChoiceDef fn]) where
reflectChoices :: Proxy cs -> [ChoiceDef String]
instance ReflectChoices '[] where
reflectChoices :: Proxy '[] -> [ChoiceDef String]
reflectChoices _ = []
instance (KnownName name, ReflectChoices cs)
=> ReflectChoices ('ChoiceDef name ': cs) where
reflectChoices :: Proxy ('ChoiceDef name : cs) -> [ChoiceDef String]
reflectChoices _ = String -> ChoiceDef String
forall fieldName. fieldName -> ChoiceDef fieldName
ChoiceDef (Proxy name -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy name
forall k (t :: k). Proxy t
Proxy @name))
ChoiceDef String -> [ChoiceDef String] -> [ChoiceDef String]
forall a. a -> [a] -> [a]
: Proxy cs -> [ChoiceDef String]
forall fn (cs :: [ChoiceDef fn]).
ReflectChoices cs =>
Proxy cs -> [ChoiceDef String]
reflectChoices (Proxy cs
forall k (t :: k). Proxy t
Proxy @cs)
class ReflectFieldType (ty :: FieldType tn) where
reflectFieldType :: Proxy ty -> FieldTypeB TypeRep String
instance ReflectFieldType 'TNull where
reflectFieldType :: Proxy 'TNull -> FieldTypeB TypeRep String
reflectFieldType _ = FieldTypeB TypeRep String
forall builtin typeName. FieldTypeB builtin typeName
TNull
instance (Typeable ty) => ReflectFieldType ('TPrimitive ty) where
reflectFieldType :: Proxy ('TPrimitive ty) -> FieldTypeB TypeRep String
reflectFieldType _ = TypeRep -> FieldTypeB TypeRep String
forall builtin typeName. builtin -> FieldTypeB builtin typeName
TPrimitive (Proxy ty -> TypeRep
forall k (proxy :: k -> *) (a :: k).
Typeable a =>
proxy a -> TypeRep
typeRep (Proxy ty
forall k (t :: k). Proxy t
Proxy @ty))
instance (KnownName nm) => ReflectFieldType ('TSchematic nm) where
reflectFieldType :: Proxy ('TSchematic nm) -> FieldTypeB TypeRep String
reflectFieldType _ = String -> FieldTypeB TypeRep String
forall builtin typeName. typeName -> FieldTypeB builtin typeName
TSchematic (Proxy nm -> String
forall k (a :: k) (proxy :: k -> *).
KnownName a =>
proxy a -> String
nameVal (Proxy nm
forall k (t :: k). Proxy t
Proxy @nm))
instance (ReflectFieldType t) => ReflectFieldType ('TOption t) where
reflectFieldType :: Proxy ('TOption t) -> FieldTypeB TypeRep String
reflectFieldType _ = FieldTypeB TypeRep String -> FieldTypeB TypeRep String
forall builtin typeName.
FieldTypeB builtin typeName -> FieldTypeB builtin typeName
TOption (Proxy t -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy t
forall k (t :: k). Proxy t
Proxy @t))
instance (ReflectFieldType t) => ReflectFieldType ('TList t) where
reflectFieldType :: Proxy ('TList t) -> FieldTypeB TypeRep String
reflectFieldType _ = FieldTypeB TypeRep String -> FieldTypeB TypeRep String
forall builtin typeName.
FieldTypeB builtin typeName -> FieldTypeB builtin typeName
TList (Proxy t -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy t
forall k (t :: k). Proxy t
Proxy @t))
instance (ReflectFieldType k, ReflectFieldType v)
=> ReflectFieldType ('TMap k v) where
reflectFieldType :: Proxy ('TMap k v) -> FieldTypeB TypeRep String
reflectFieldType _ = FieldTypeB TypeRep String
-> FieldTypeB TypeRep String -> FieldTypeB TypeRep String
forall builtin typeName.
FieldTypeB builtin typeName
-> FieldTypeB builtin typeName -> FieldTypeB builtin typeName
TMap (Proxy k -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy k
forall k (t :: k). Proxy t
Proxy @k)) (Proxy v -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy v
forall k (t :: k). Proxy t
Proxy @v))
instance (ReflectFieldTypes ts) => ReflectFieldType ('TUnion ts) where
reflectFieldType :: Proxy ('TUnion ts) -> FieldTypeB TypeRep String
reflectFieldType _ = [FieldTypeB TypeRep String] -> FieldTypeB TypeRep String
forall builtin typeName.
[FieldTypeB builtin typeName] -> FieldTypeB builtin typeName
TUnion (Proxy ts -> [FieldTypeB TypeRep String]
forall tn (ts :: [FieldType tn]).
ReflectFieldTypes ts =>
Proxy ts -> [FieldTypeB TypeRep String]
reflectFieldTypes (Proxy ts
forall k (t :: k). Proxy t
Proxy @ts))
class ReflectFieldTypes (ts :: [FieldType tn]) where
reflectFieldTypes :: Proxy ts -> [FieldTypeB TypeRep String]
instance ReflectFieldTypes '[] where
reflectFieldTypes :: Proxy '[] -> [FieldTypeB TypeRep String]
reflectFieldTypes _ = []
instance (ReflectFieldType t, ReflectFieldTypes ts)
=> ReflectFieldTypes (t ': ts) where
reflectFieldTypes :: Proxy (t : ts) -> [FieldTypeB TypeRep String]
reflectFieldTypes _ = Proxy t -> FieldTypeB TypeRep String
forall tn (ty :: FieldType tn).
ReflectFieldType ty =>
Proxy ty -> FieldTypeB TypeRep String
reflectFieldType (Proxy t
forall k (t :: k). Proxy t
Proxy @t) FieldTypeB TypeRep String
-> [FieldTypeB TypeRep String] -> [FieldTypeB TypeRep String]
forall a. a -> [a] -> [a]
: Proxy ts -> [FieldTypeB TypeRep String]
forall tn (ts :: [FieldType tn]).
ReflectFieldTypes ts =>
Proxy ts -> [FieldTypeB TypeRep String]
reflectFieldTypes (Proxy ts
forall k (t :: k). Proxy t
Proxy @ts)