constraints-0.14: src/Data/Constraint/Char.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE CPP #-}
-- | Utilities for working with 'KnownChar' constraints.
--
-- This module is only available on GHC 9.2 or later.
module Data.Constraint.Char
( CharToNat
, NatToChar
, charToNat
, natToChar
) where
import Data.Char
import Data.Constraint
import Data.Proxy
import GHC.TypeLits
#if MIN_VERSION_base(4,18,0)
import Data.Constraint.Unsafe
import qualified GHC.TypeNats as TN
#else
import Unsafe.Coerce
#endif
-- implementation details
#if !MIN_VERSION_base(4,18,0)
newtype Magic c = Magic (KnownChar c => Dict (KnownChar c))
#endif
magicCN :: forall c n. (Char -> Int) -> KnownChar c :- KnownNat n
#if MIN_VERSION_base(4,18,0)
magicCN f = Sub $ TN.withKnownNat (unsafeSNat @n (fromIntegral (f (charVal (Proxy @c))))) Dict
#else
magicCN f = Sub $ unsafeCoerce (Magic Dict) (fromIntegral @Int @Natural (f (charVal (Proxy @c))))
#endif
magicNC :: forall n c. (Int -> Char) -> KnownNat n :- KnownChar c
#if MIN_VERSION_base(4,18,0)
magicNC f = Sub $ withKnownChar (unsafeSChar @c (f (fromIntegral (natVal (Proxy @n))))) Dict
#else
magicNC f = Sub $ unsafeCoerce (Magic Dict) (f (fromIntegral (natVal (Proxy @n))))
#endif
-- operations
charToNat :: forall c. KnownChar c :- KnownNat (CharToNat c)
charToNat = magicCN ord
-- NB: 0x10FFFF the maximum value for a Unicode code point. Calling `chr` on
-- anything greater will throw an exception.
natToChar :: forall n. (n <= 0x10FFFF, KnownNat n) :- KnownChar (NatToChar n)
natToChar = Sub $ case magicNC @n @(NatToChar n) chr of Sub r -> r