cfg-0.0.2.0: src/Cfg/Deriving/Assert.hs
-- |
-- Module : Cfg.Deriving.Assert
-- Copyright : © Jonathan Lorimer, 2023
-- License : MIT
-- Maintainer : jonathanlorimer@pm.me
-- Stability : stable
--
-- @since 0.0.2.0
--
-- This module provides type level assertions so that we can constrain the
-- instances user's can create, and give them good error messages
module Cfg.Deriving.Assert where
import Data.Kind (Type)
import GHC.Base (Constraint)
import GHC.Generics
import GHC.TypeError (ErrorMessage (..), TypeError)
-- | A type level helper for creating custom error messages based on a predicate
--
-- @since 0.0.2.0
class Assert (pred :: Bool) (msg :: ErrorMessage)
instance Assert 'True msg
instance (TypeError msg ~ '()) => Assert 'False msg
-- | A type level predicate that helps us identify top level product types
--
-- @since 0.0.2.0
type family IsTopLevelRecord f where
IsTopLevelRecord V1 = 'False
IsTopLevelRecord U1 = 'False
IsTopLevelRecord (K1 i c) = 'False
IsTopLevelRecord (M1 D c f) = IsTopLevelRecord f
IsTopLevelRecord (M1 C c f) = IsTopLevelRecord f
IsTopLevelRecord (M1 S c f) = 'True
IsTopLevelRecord (f :*: g) = IsTopLevelRecord f
IsTopLevelRecord (f :+: g) = 'False
-- | A custom error message for non-top-level records
--
-- @since 0.0.2.0
type AssertTopLevelRecord (constraint :: Type -> Constraint) a =
Assert
(IsTopLevelRecord (Rep a))
( 'Text "🚫 Cannot derive "
':<>: 'ShowType constraint
':<>: 'Text " instance for "
':<>: 'ShowType a
':$$: ( 'Text "💡 "
':<>: 'ShowType constraint
':<>: 'Text " must be derived on a top level record type with named fields."
)
)