{-# LANGUAGE FlexibleInstances, TypeSynonymInstances, OverloadedStrings #-}
module Web.PathPieces
    ( PathPiece (..)
    , PathMultiPiece (..)
    , readFromPathPiece
    , showToPathPiece
    -- * Deprecated
    , toSinglePiece
    , toMultiPiece
    , fromSinglePiece
    , fromMultiPiece
    ) where

import Data.Int (Int8, Int16, Int32, Int64)
import Data.Word (Word, Word8, Word16, Word32, Word64)
import qualified Data.Text as S
import qualified Data.Text.Lazy as L
import qualified Data.Text.Read
import Data.Time (Day)
import Control.Exception (assert)
import Text.Read (readMaybe)

class PathPiece s where
    fromPathPiece :: S.Text -> Maybe s
    toPathPiece :: s -> S.Text

instance PathPiece () where
    fromPathPiece :: Text -> Maybe ()
fromPathPiece Text
t = if Text
t forall a. Eq a => a -> a -> Bool
== Text
"_" then forall a. a -> Maybe a
Just () else forall a. Maybe a
Nothing
    toPathPiece :: () -> Text
toPathPiece () = Text
"_"

instance PathPiece String where
    fromPathPiece :: Text -> Maybe String
fromPathPiece = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
S.unpack
    toPathPiece :: String -> Text
toPathPiece = String -> Text
S.pack

instance PathPiece S.Text where
    fromPathPiece :: Text -> Maybe Text
fromPathPiece = forall a. a -> Maybe a
Just
    toPathPiece :: Text -> Text
toPathPiece = forall a. a -> a
id

instance PathPiece L.Text where
    fromPathPiece :: Text -> Maybe Text
fromPathPiece = forall a. a -> Maybe a
Just forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Text
L.fromChunks forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. Monad m => a -> m a
return
    toPathPiece :: Text -> Text
toPathPiece = [Text] -> Text
S.concat forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> [Text]
L.toChunks

parseIntegral :: (Integral a, Bounded a, Ord a) => S.Text -> Maybe a
parseIntegral :: forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral Text
s = Maybe a
n
    where
    n :: Maybe a
n = case forall a. Num a => Reader a -> Reader a
Data.Text.Read.signed forall a. Integral a => Reader a
Data.Text.Read.decimal Text
s of
        Right (Integer
i, Text
"") | Integer
i forall a. Ord a => a -> a -> Bool
<= Integer
top Bool -> Bool -> Bool
&& Integer
i forall a. Ord a => a -> a -> Bool
>= Integer
bot -> forall a. a -> Maybe a
Just (forall a. Num a => Integer -> a
fromInteger Integer
i)
        Either String (Integer, Text)
_ -> forall a. Maybe a
Nothing
    Just a
witness = Maybe a
n
    top :: Integer
top = forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
maxBound forall a. a -> a -> a
`asTypeOf` a
witness)
    bot :: Integer
bot = forall a. Integral a => a -> Integer
toInteger (forall a. Bounded a => a
minBound forall a. a -> a -> a
`asTypeOf` a
witness)

instance PathPiece Integer where
    fromPathPiece :: Text -> Maybe Integer
fromPathPiece Text
s =
        case forall a. Num a => Reader a -> Reader a
Data.Text.Read.signed forall a. Integral a => Reader a
Data.Text.Read.decimal Text
s of
            Right (Integer
i, Text
"") -> forall a. a -> Maybe a
Just Integer
i
            Either String (Integer, Text)
_ -> forall a. Maybe a
Nothing
    toPathPiece :: Integer -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Int where
    fromPathPiece :: Text -> Maybe Int
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Int -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Int8 where
    fromPathPiece :: Text -> Maybe Int8
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Int8 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Int16 where
    fromPathPiece :: Text -> Maybe Int16
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Int16 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Int32 where
    fromPathPiece :: Text -> Maybe Int32
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Int32 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Int64 where
    fromPathPiece :: Text -> Maybe Int64
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Int64 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Word where
    fromPathPiece :: Text -> Maybe Word
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Word -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Word8 where
    fromPathPiece :: Text -> Maybe Word8
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Word8 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Word16 where
    fromPathPiece :: Text -> Maybe Word16
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Word16 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Word32 where
    fromPathPiece :: Text -> Maybe Word32
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Word32 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Word64 where
    fromPathPiece :: Text -> Maybe Word64
fromPathPiece = forall a. (Integral a, Bounded a, Ord a) => Text -> Maybe a
parseIntegral
    toPathPiece :: Word64 -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Bool where
    fromPathPiece :: Text -> Maybe Bool
fromPathPiece Text
t =
        case forall a. (a -> Bool) -> [a] -> [a]
filter (forall (t :: * -> *) a. Foldable t => t a -> Bool
null forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd) forall a b. (a -> b) -> a -> b
$ forall a. Read a => ReadS a
reads forall a b. (a -> b) -> a -> b
$ Text -> String
S.unpack Text
t of
            (Bool
a, String
s):[(Bool, String)]
_ -> forall a. (?callStack::CallStack) => Bool -> a -> a
assert (forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
s) (forall a. a -> Maybe a
Just Bool
a)
            [(Bool, String)]
_        -> forall a. Maybe a
Nothing
    toPathPiece :: Bool -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance PathPiece Day where
    fromPathPiece :: Text -> Maybe Day
fromPathPiece Text
t =
        case forall a. Read a => ReadS a
reads forall a b. (a -> b) -> a -> b
$ Text -> String
S.unpack Text
t of
            [(Day
a,String
"")] -> forall a. a -> Maybe a
Just Day
a
            [(Day, String)]
_ -> forall a. Maybe a
Nothing
    toPathPiece :: Day -> Text
toPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

instance (PathPiece a) => PathPiece (Maybe a) where
    fromPathPiece :: Text -> Maybe (Maybe a)
fromPathPiece Text
s = case Text -> Text -> Maybe Text
S.stripPrefix Text
"Just " Text
s of
        Just Text
r -> forall a. a -> Maybe a
Just forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` forall s. PathPiece s => Text -> Maybe s
fromPathPiece Text
r
        Maybe Text
_ -> case Text
s of
            Text
"Nothing" -> forall a. a -> Maybe a
Just forall a. Maybe a
Nothing
            Text
_ -> forall a. Maybe a
Nothing
    toPathPiece :: Maybe a -> Text
toPathPiece Maybe a
m = case Maybe a
m of
        Just a
s -> Text
"Just " Text -> Text -> Text
`S.append` forall s. PathPiece s => s -> Text
toPathPiece a
s
        Maybe a
_ -> Text
"Nothing"

class PathMultiPiece s where
    fromPathMultiPiece :: [S.Text] -> Maybe s
    toPathMultiPiece :: s -> [S.Text]

instance PathPiece a => PathMultiPiece [a] where
    fromPathMultiPiece :: [Text] -> Maybe [a]
fromPathMultiPiece = forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
(a -> m b) -> t a -> m (t b)
mapM forall s. PathPiece s => Text -> Maybe s
fromPathPiece
    toPathMultiPiece :: [a] -> [Text]
toPathMultiPiece = forall a b. (a -> b) -> [a] -> [b]
map forall s. PathPiece s => s -> Text
toPathPiece

-- | A function for helping generate free 'PathPiece'
--   instances for enumeration data types 
--   that have derived 'Read' and 'Show' instances.
--   Intended to be used like this:
--
--   > data MyData = Foo | Bar | Baz
--   >   deriving (Read,Show)
--   > instance PathPiece MyData where
--   >   fromPathPiece = readFromPathPiece
--   >   toPathPiece = showToPathPiece
--
--  Since 0.2.1. 
readFromPathPiece :: Read s => S.Text -> Maybe s
readFromPathPiece :: forall s. Read s => Text -> Maybe s
readFromPathPiece = forall a. Read a => String -> Maybe a
readMaybe forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> String
S.unpack

-- | See the documentation for 'readFromPathPiece'.
--
--  Since 0.2.1. 
showToPathPiece :: Show s => s -> S.Text
showToPathPiece :: forall s. Show s => s -> Text
showToPathPiece = String -> Text
S.pack forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Show a => a -> String
show

{-# DEPRECATED toSinglePiece "Use toPathPiece instead of toSinglePiece" #-}
toSinglePiece :: PathPiece p => p -> S.Text
toSinglePiece :: forall s. PathPiece s => s -> Text
toSinglePiece = forall s. PathPiece s => s -> Text
toPathPiece

{-# DEPRECATED fromSinglePiece "Use fromPathPiece instead of fromSinglePiece" #-}
fromSinglePiece :: PathPiece p => S.Text -> Maybe p
fromSinglePiece :: forall s. PathPiece s => Text -> Maybe s
fromSinglePiece = forall s. PathPiece s => Text -> Maybe s
fromPathPiece

{-# DEPRECATED toMultiPiece "Use toPathMultiPiece instead of toMultiPiece" #-}
toMultiPiece :: PathMultiPiece ps => ps -> [S.Text]
toMultiPiece :: forall ps. PathMultiPiece ps => ps -> [Text]
toMultiPiece = forall ps. PathMultiPiece ps => ps -> [Text]
toPathMultiPiece

{-# DEPRECATED fromMultiPiece "Use fromPathMultiPiece instead of fromMultiPiece" #-}
fromMultiPiece :: PathMultiPiece ps => [S.Text] -> Maybe ps
fromMultiPiece :: forall ps. PathMultiPiece ps => [Text] -> Maybe ps
fromMultiPiece = forall ps. PathMultiPiece ps => [Text] -> Maybe ps
fromPathMultiPiece