readable-0.3.0.1: src/Data/Readable.hs
{-# LANGUAGE OverloadedStrings #-}
{-|
The Read type class is very useful for building data types from String
representations. But String has high overhead, so sometimes it isn't suitable
for applications where space usage and performance are important. This
library provides a simpler version of Read's functionality for Text and
ByteStrings.
-}
module Data.Readable
( Readable(..)
) where
------------------------------------------------------------------------------
import Control.Monad
import Data.ByteString.Char8 (ByteString)
import Data.Int
import Data.Text (Text)
import qualified Data.Text as T
import Data.Text.Encoding
import Data.Text.Read
import Data.Word
------------------------------------------------------------------------------
-- | ByteString and Text reading using MonadPlus to handle parse failure. On
-- error, fromText and fromBS will return mzero. You can use mplus to provide
-- fallback defaults.
class Readable a where
-- | Reads data from a Text representation.
fromText :: MonadPlus m => Text -> m a
-- | Reads data from a UTF8 encoded ByteString. The default
-- implementation of this function simply decodes with UTF-8 and then
-- calls the fromText function. If decoding fails, mzero will be
-- returned. You can provide your own implementation if you need
-- different behavior.
fromBS :: MonadPlus m => ByteString -> m a
fromBS = fromText <=< hushPlus . decodeUtf8'
hushPlus :: MonadPlus m => Either a b -> m b
hushPlus (Left _) = mzero
hushPlus (Right b) = return b
------------------------------------------------------------------------------
-- | Fails if the input wasn't parsed completely.
checkComplete :: MonadPlus m => (t, Text) -> m t
checkComplete (a,rest)
| T.null rest = return a
| otherwise = mzero
-- We don't supply instances for Text or ByteString anymore because they're
-- almost definitely not what the user would want. Users should use the
-- appropriate encodeUtf8/decodeUtf8 functions instead.
instance Readable Int where
fromText = either (const mzero) checkComplete . signed decimal
instance Readable Integer where
fromText = either (const mzero) checkComplete . signed decimal
instance Readable Float where
fromText = either (const mzero) checkComplete . rational
instance Readable Double where
fromText = either (const mzero) checkComplete . double
instance Readable Bool where
fromText t = case T.toLower t of
"1" -> return True
"0" -> return False
"t" -> return True
"f" -> return False
"true" -> return True
"false" -> return False
"y" -> return True
"n" -> return False
"yes" -> return True
"no" -> return False
_ -> mzero
instance Readable Int8 where
fromText = either (const mzero) checkComplete . signed decimal
instance Readable Int16 where
fromText = either (const mzero) checkComplete . signed decimal
instance Readable Int32 where
fromText = either (const mzero) checkComplete . signed decimal
instance Readable Int64 where
fromText = either (const mzero) checkComplete . signed decimal
instance Readable Word8 where
fromText = either (const mzero) checkComplete . decimal
instance Readable Word16 where
fromText = either (const mzero) checkComplete . decimal
instance Readable Word32 where
fromText = either (const mzero) checkComplete . decimal
instance Readable Word64 where
fromText = either (const mzero) checkComplete . decimal