{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE TypeSynonymInstances #-} module Servant.Common.Text ( FromText(..) , ToText(..) ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative ((<$>)) #endif import Data.Int (Int16, Int32, Int64, Int8) import Data.String.Conversions (cs) import Data.Text (Text) import Data.Text.Read (Reader, decimal, rational, signed) import Data.Word (Word16, Word32, Word64, Word8 #if !MIN_VERSION_base(4,8,0) , Word #endif ) -- | For getting values from url captures and query string parameters -- Instances should obey: -- > fromText (toText a) == Just a class FromText a where fromText :: Text -> Maybe a -- | For putting values in paths and query string parameters -- Instances should obey: -- > fromText (toText a) == Just a class ToText a where toText :: a -> Text instance FromText Text where fromText = Just instance ToText Text where toText = id instance FromText String where fromText = Just . cs instance ToText String where toText = cs -- | -- >>> fromText ("true"::Text) :: Maybe Bool -- Just True -- >>> fromText ("false"::Text) :: Maybe Bool -- Just False -- >>> fromText ("anything else"::Text) :: Maybe Bool -- Nothing instance FromText Bool where fromText "true" = Just True fromText "false" = Just False fromText _ = Nothing -- | -- >>> toText True -- "true" -- >>> toText False -- "false" instance ToText Bool where toText True = "true" toText False = "false" instance FromText Int where fromText = runReader (signed decimal) instance ToText Int where toText = cs . show instance FromText Int8 where fromText = runReader (signed decimal) instance ToText Int8 where toText = cs . show instance FromText Int16 where fromText = runReader (signed decimal) instance ToText Int16 where toText = cs . show instance FromText Int32 where fromText = runReader (signed decimal) instance ToText Int32 where toText = cs . show instance FromText Int64 where fromText = runReader (signed decimal) instance ToText Int64 where toText = cs . show instance FromText Word where fromText = runReader decimal instance ToText Word where toText = cs . show instance FromText Word8 where fromText = runReader decimal instance ToText Word8 where toText = cs . show instance FromText Word16 where fromText = runReader decimal instance ToText Word16 where toText = cs . show instance FromText Word32 where fromText = runReader decimal instance ToText Word32 where toText = cs . show instance FromText Word64 where fromText = runReader decimal instance ToText Word64 where toText = cs . show instance FromText Integer where fromText = runReader (signed decimal) instance ToText Integer where toText = cs . show instance FromText Double where fromText x = fromRational <$> runReader rational x instance ToText Double where toText = cs . show instance FromText Float where -- Double is more practically accurate due to weird rounding when using -- rational. We convert to double and then convert to Float. fromText x = fromRational <$> runReader rational x instance ToText Float where toText = cs . show runReader :: Reader a -> Text -> Maybe a runReader reader t = either (const Nothing) (Just . fst) $ reader t