packages feed

servant-benchmark-0.1.0.0: src/Servant/Benchmark/ToText.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE UndecidableInstances #-}

module Servant.Benchmark.ToText (ToText (..)) where

import qualified Data.ByteString as BS
import Data.Data (Proxy (Proxy))
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import Network.HTTP.Types (Method)

-- | Types that can be converted to Text and serialized.
class ToText a where
    toText :: a -> T.Text

instance (HasText a ~ textType, HasTextRepresentation textType a) => ToText a where
    toText = typeToText (Proxy @textType)

-- Types that have a Text representation as defined by the HasText type family.
-- The class helps to avoid using `show` on types that can be easily converted to `Text`
class HasTextRepresentation (s :: TextType) a where
    typeToText :: Proxy s -> a -> T.Text

instance HasTextRepresentation 'TypeString String where
    typeToText _ = T.pack

instance HasTextRepresentation 'TypeText T.Text where
    typeToText _ = id

instance HasTextRepresentation 'TypeByteString BS.ByteString where
    typeToText _ = T.decodeUtf8

instance HasTextRepresentation 'TypeMethod Method where
    typeToText _ = T.decodeUtf8

instance Show a => HasTextRepresentation 'TypeShow a where
    typeToText _ = T.pack . show

data TextType
    = TypeString
    | TypeText
    | TypeByteString
    | TypeMethod
    | TypeShow

type family HasText a where
    HasText String = 'TypeString
    HasText T.Text = 'TypeText
    HasText BS.ByteString = 'TypeByteString
    HasText a = 'TypeShow