{-# LANGUAGE DataKinds #-}
{-# LANGUAGE ExplicitNamespaces #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE Trustworthy #-}
module Data.Parameterized.SymbolRepr
  ( 
    SymbolRepr
  , symbolRepr
  , knownSymbol
  , someSymbol
    
  , type GHC.Symbol
  , GHC.KnownSymbol
  ) where
import GHC.TypeLits as GHC
import Unsafe.Coerce (unsafeCoerce)
import Data.Hashable
import Data.Proxy
import qualified Data.Text as Text
import Data.Parameterized.Classes
import Data.Parameterized.Some
newtype SymbolRepr (nm::GHC.Symbol)
  = SymbolRepr { symbolRepr :: Text.Text
                 
               }
someSymbol :: Text.Text -> Some SymbolRepr
someSymbol nm = Some (SymbolRepr nm)
knownSymbol :: GHC.KnownSymbol s => SymbolRepr s
knownSymbol = go Proxy
  where go :: GHC.KnownSymbol s => Proxy s -> SymbolRepr s
        go p = SymbolRepr $! packSymbol (GHC.symbolVal p)
        
        
        
        packSymbol str
           | Text.unpack txt == str = txt
           | otherwise = error $ "Unrepresentable symbol! "++ str
         where txt = Text.pack str
instance (GHC.KnownSymbol s) => KnownRepr SymbolRepr s where
  knownRepr = knownSymbol
instance TestEquality SymbolRepr where
   testEquality (SymbolRepr x :: SymbolRepr x) (SymbolRepr y)
      | x == y    = Just (unsafeCoerce (Refl :: x :~: x))
      | otherwise = Nothing
instance OrdF SymbolRepr where
   compareF (SymbolRepr x :: SymbolRepr x) (SymbolRepr y)
      | x <  y    = LTF
      | x == y    = unsafeCoerce (EQF :: OrderingF x x)
      | otherwise = GTF
instance Eq (SymbolRepr x) where
   _ == _ = True
instance Ord (SymbolRepr x) where
   compare _ _ = EQ
instance HashableF SymbolRepr where
  hashWithSaltF = hashWithSalt
instance Hashable (SymbolRepr nm) where
  hashWithSalt s (SymbolRepr nm) = hashWithSalt s nm
instance Show (SymbolRepr nm) where
  show (SymbolRepr nm) = Text.unpack nm
instance ShowF SymbolRepr