module Language.LSP.Protocol.Types.Singletons where import Control.DeepSeq import Data.Aeson import Data.Hashable import Data.Proxy import Data.Text qualified as T import GHC.TypeLits ( KnownNat, KnownSymbol, Nat, Symbol, natVal, symbolVal, ) import Prettyprinter {- | A type whose only inhabitant is a single, statically-known string. This corresponds to types like @"hello"@ in the LSP specification that are exactly types with a single inhabitant. -} data AString (s :: Symbol) where AString :: KnownSymbol s => AString s instance Show (AString s) where show AString = symbolVal (Proxy @s) instance Pretty (AString s) where pretty = viaShow instance Eq (AString s) where _ == _ = True instance Ord (AString s) where compare _ _ = EQ instance NFData (AString s) where rnf a = seq a () instance Hashable (AString sym) where hashWithSalt s AString = hashWithSalt s (symbolVal (Proxy @sym)) instance ToJSON (AString s) where toJSON AString = toJSON (T.pack (symbolVal (Proxy @s))) instance KnownSymbol s => FromJSON (AString s) where parseJSON = withText "string literal type" $ \s -> do let sym = symbolVal (Proxy @s) if s == T.pack sym then pure AString else fail $ "wrong string, got: " <> show s <> " expected " <> sym {- | A type whose only inhabitant is a single, statically-known integer. This corresponds to types like @1@ in the LSP specification that are exactly types with a single inhabitant. -} data AnInteger (n :: Nat) where AnInteger :: KnownNat n => AnInteger n instance Show (AnInteger n) where show AnInteger = show $ natVal (Proxy @n) instance Pretty (AnInteger n) where pretty = viaShow instance Eq (AnInteger n) where _ == _ = True instance Ord (AnInteger n) where compare _ _ = EQ instance NFData (AnInteger s) where rnf a = seq a () instance Hashable (AnInteger i) where hashWithSalt s AnInteger = hashWithSalt s (natVal (Proxy @i)) instance ToJSON (AnInteger n) where toJSON AnInteger = toJSON (natVal (Proxy @n)) instance KnownNat n => FromJSON (AnInteger n) where parseJSON = withScientific "integer literal type" $ \n -> do let nat = natVal (Proxy @n) if truncate n == nat then pure AnInteger else fail $ "wrong integer, got: " <> show n <> " expected " <> show nat