    {-# 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 such as not decoding to UTF8.
        fromBS   :: MonadPlus m => ByteString -> m a
        fromBS = Text -> m a
    forall a (m :: * -> *). (Readable a, MonadPlus m) => Text -> m a
    forall (m :: * -> *). MonadPlus m => Text -> m a
    fromText (Text -> m a) -> (ByteString -> m Text) -> ByteString -> m a
    forall (m :: * -> *) b c a.
    Monad m =>
    (b -> m c) -> (a -> m b) -> a -> m c
    <=< Either UnicodeException Text -> m Text
    forall (m :: * -> *) a b. MonadPlus m => Either a b -> m b
    hushPlus (Either UnicodeException Text -> m Text)
    -> (ByteString -> Either UnicodeException Text)
    -> ByteString
    -> m Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ByteString -> Either UnicodeException Text
    decodeUtf8'

    hushPlus :: MonadPlus m => Either a b -> m b
    hushPlus :: forall (m :: * -> *) a b. MonadPlus m => Either a b -> m b
    hushPlus (Left a
    _) = m b
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero
    hushPlus (Right b
    b) = b -> m b
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return b
    b

    ------------------------------------------------------------------------------
    -- | Fails if the input wasn't parsed completely.
    checkComplete :: MonadPlus m => (t, Text) -> m t
    checkComplete :: forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (t
    a,Text
    rest)
      | Text -> Bool
    T.null Text
    rest = t -> m t
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return t
    a
      | Bool
    otherwise   = m t
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero

    -- Leaving out these instances breaks users who depend on having a unified
    -- constraint for parsing, so we need to keep them around.
    instance Readable ByteString where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m ByteString
    fromText = ByteString -> m ByteString
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (ByteString -> m ByteString)
    -> (Text -> ByteString) -> Text -> m ByteString
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> ByteString
    encodeUtf8
        fromBS :: forall (m :: * -> *). MonadPlus m => ByteString -> m ByteString
    fromBS = ByteString -> m ByteString
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
    instance Readable Text where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Text
    fromText = Text -> m Text
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return

    instance Readable Int where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Int
    fromText = (String -> m Int)
    -> ((Int, Text) -> m Int) -> Either String (Int, Text) -> m Int
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Int -> String -> m Int
    forall a b. a -> b -> a
    const m Int
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Int, Text) -> m Int
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Int, Text) -> m Int)
    -> (Text -> Either String (Int, Text)) -> Text -> m Int
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Either String (Int, Text))
    -> Text -> Either String (Int, Text)
    forall a. Num a => Reader a -> Reader a
    signed Text -> Either String (Int, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Integer where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Integer
    fromText = (String -> m Integer)
    -> ((Integer, Text) -> m Integer)
    -> Either String (Integer, Text)
    -> m Integer
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Integer -> String -> m Integer
    forall a b. a -> b -> a
    const m Integer
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Integer, Text) -> m Integer
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Integer, Text) -> m Integer)
    -> (Text -> Either String (Integer, Text)) -> Text -> m Integer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Either String (Integer, Text))
    -> Text -> Either String (Integer, Text)
    forall a. Num a => Reader a -> Reader a
    signed Text -> Either String (Integer, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Float where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Float
    fromText = (String -> m Float)
    -> ((Float, Text) -> m Float)
    -> Either String (Float, Text)
    -> m Float
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Float -> String -> m Float
    forall a b. a -> b -> a
    const m Float
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Float, Text) -> m Float
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Float, Text) -> m Float)
    -> (Text -> Either String (Float, Text)) -> Text -> m Float
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Either String (Float, Text)
    forall a. Fractional a => Reader a
    rational
    instance Readable Double where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Double
    fromText = (String -> m Double)
    -> ((Double, Text) -> m Double)
    -> Either String (Double, Text)
    -> m Double
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Double -> String -> m Double
    forall a b. a -> b -> a
    const m Double
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Double, Text) -> m Double
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Double, Text) -> m Double)
    -> (Text -> Either String (Double, Text)) -> Text -> m Double
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Either String (Double, Text)
    double
    instance Readable Bool where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Bool
    fromText Text
    t = case Text -> Text
    T.toLower Text
    t of
                       Text
    "1" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
                       Text
    "0" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False
                       Text
    "t" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
                       Text
    "f" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False
                       Text
    "true" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
                       Text
    "false" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False
                       Text
    "y" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
                       Text
    "n" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False
                       Text
    "yes" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    True
                       Text
    "no" -> Bool -> m Bool
    forall a. a -> m a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Bool
    False
                       Text
    _ -> m Bool
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero

    instance Readable Int8 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Int8
    fromText = (String -> m Int8)
    -> ((Int8, Text) -> m Int8) -> Either String (Int8, Text) -> m Int8
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Int8 -> String -> m Int8
    forall a b. a -> b -> a
    const m Int8
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Int8, Text) -> m Int8
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Int8, Text) -> m Int8)
    -> (Text -> Either String (Int8, Text)) -> Text -> m Int8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Either String (Int8, Text))
    -> Text -> Either String (Int8, Text)
    forall a. Num a => Reader a -> Reader a
    signed Text -> Either String (Int8, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Int16 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Int16
    fromText = (String -> m Int16)
    -> ((Int16, Text) -> m Int16)
    -> Either String (Int16, Text)
    -> m Int16
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Int16 -> String -> m Int16
    forall a b. a -> b -> a
    const m Int16
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Int16, Text) -> m Int16
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Int16, Text) -> m Int16)
    -> (Text -> Either String (Int16, Text)) -> Text -> m Int16
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Either String (Int16, Text))
    -> Text -> Either String (Int16, Text)
    forall a. Num a => Reader a -> Reader a
    signed Text -> Either String (Int16, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Int32 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Int32
    fromText = (String -> m Int32)
    -> ((Int32, Text) -> m Int32)
    -> Either String (Int32, Text)
    -> m Int32
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Int32 -> String -> m Int32
    forall a b. a -> b -> a
    const m Int32
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Int32, Text) -> m Int32
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Int32, Text) -> m Int32)
    -> (Text -> Either String (Int32, Text)) -> Text -> m Int32
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Either String (Int32, Text))
    -> Text -> Either String (Int32, Text)
    forall a. Num a => Reader a -> Reader a
    signed Text -> Either String (Int32, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Int64 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Int64
    fromText = (String -> m Int64)
    -> ((Int64, Text) -> m Int64)
    -> Either String (Int64, Text)
    -> m Int64
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Int64 -> String -> m Int64
    forall a b. a -> b -> a
    const m Int64
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Int64, Text) -> m Int64
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Int64, Text) -> m Int64)
    -> (Text -> Either String (Int64, Text)) -> Text -> m Int64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> Either String (Int64, Text))
    -> Text -> Either String (Int64, Text)
    forall a. Num a => Reader a -> Reader a
    signed Text -> Either String (Int64, Text)
    forall a. Integral a => Reader a
    decimal

    instance Readable Word8 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Word8
    fromText = (String -> m Word8)
    -> ((Word8, Text) -> m Word8)
    -> Either String (Word8, Text)
    -> m Word8
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Word8 -> String -> m Word8
    forall a b. a -> b -> a
    const m Word8
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Word8, Text) -> m Word8
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Word8, Text) -> m Word8)
    -> (Text -> Either String (Word8, Text)) -> Text -> m Word8
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Either String (Word8, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Word16 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Word16
    fromText = (String -> m Word16)
    -> ((Word16, Text) -> m Word16)
    -> Either String (Word16, Text)
    -> m Word16
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Word16 -> String -> m Word16
    forall a b. a -> b -> a
    const m Word16
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Word16, Text) -> m Word16
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Word16, Text) -> m Word16)
    -> (Text -> Either String (Word16, Text)) -> Text -> m Word16
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Either String (Word16, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Word32 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Word32
    fromText = (String -> m Word32)
    -> ((Word32, Text) -> m Word32)
    -> Either String (Word32, Text)
    -> m Word32
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Word32 -> String -> m Word32
    forall a b. a -> b -> a
    const m Word32
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Word32, Text) -> m Word32
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Word32, Text) -> m Word32)
    -> (Text -> Either String (Word32, Text)) -> Text -> m Word32
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Either String (Word32, Text)
    forall a. Integral a => Reader a
    decimal
    instance Readable Word64 where
        fromText :: forall (m :: * -> *). MonadPlus m => Text -> m Word64
    fromText = (String -> m Word64)
    -> ((Word64, Text) -> m Word64)
    -> Either String (Word64, Text)
    -> m Word64
    forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
    either (m Word64 -> String -> m Word64
    forall a b. a -> b -> a
    const m Word64
    forall a. m a
    forall (m :: * -> *) a. MonadPlus m => m a
    mzero) (Word64, Text) -> m Word64
    forall (m :: * -> *) t. MonadPlus m => (t, Text) -> m t
    checkComplete (Either String (Word64, Text) -> m Word64)
    -> (Text -> Either String (Word64, Text)) -> Text -> m Word64
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Either String (Word64, Text)
    forall a. Integral a => Reader a
    decimal