{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE KindSignatures      #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies        #-}
{-# LANGUAGE TypeOperators       #-}
module Servant.API.Modifiers (
    
    Required, Optional,
    FoldRequired, FoldRequired',
    
    Lenient, Strict,
    FoldLenient, FoldLenient',
    
    RequiredArgument,
    foldRequiredArgument,
    unfoldRequiredArgument,
    RequestArgument,
    unfoldRequestArgument,
    ) where
import           Data.Proxy
                 (Proxy (..))
import           Data.Singletons.Bool
                 (SBool (..), SBoolI (..))
import           Data.Text
                 (Text)
import           Data.Type.Bool
                 (If)
data Required
data Optional
type FoldRequired mods = FoldRequired' 'False mods
type family FoldRequired' (acc :: Bool) (mods :: [*]) :: Bool where
    FoldRequired' acc '[]                = acc
    FoldRequired' acc (Required ': mods) = FoldRequired' 'True mods
    FoldRequired' acc (Optional ': mods) = FoldRequired' 'False mods
    FoldRequired' acc (mod      ': mods) = FoldRequired' acc mods
data Lenient
data Strict
type FoldLenient mods = FoldLenient' 'False mods
type family FoldLenient' (acc :: Bool) (mods ::  [*]) :: Bool where
    FoldLenient' acc '[]               = acc
    FoldLenient' acc (Lenient ': mods) = FoldLenient' 'True mods
    FoldLenient' acc (Strict  ': mods) = FoldLenient' 'False mods
    FoldLenient' acc (mod     ': mods) = FoldLenient' acc mods
type RequiredArgument mods a = If (FoldRequired mods) a (Maybe a)
foldRequiredArgument
    :: forall mods a r. (SBoolI (FoldRequired mods))
    => Proxy mods
    -> (a -> r)        
    -> (Maybe a -> r)  
    -> RequiredArgument mods a
    -> r
foldRequiredArgument :: forall (mods :: [*]) a r.
SBoolI (FoldRequired mods) =>
Proxy mods
-> (a -> r) -> (Maybe a -> r) -> RequiredArgument mods a -> r
foldRequiredArgument Proxy mods
_ a -> r
f Maybe a -> r
g RequiredArgument mods a
mx =
    case (forall (b :: Bool). SBoolI b => SBool b
sbool :: SBool (FoldRequired mods), RequiredArgument mods a
mx) of
        (SBool (FoldRequired mods)
STrue, RequiredArgument mods a
x)  -> a -> r
f RequiredArgument mods a
x
        (SBool (FoldRequired mods)
SFalse, RequiredArgument mods a
x) -> Maybe a -> r
g RequiredArgument mods a
x
unfoldRequiredArgument
    :: forall mods m a. (Monad m, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods))
    => Proxy mods
    -> m (RequiredArgument mods a)            
    -> (Text -> m (RequiredArgument mods a))  
    -> Maybe (Either Text a)                  
    -> m (RequiredArgument mods a)
unfoldRequiredArgument :: forall (mods :: [*]) (m :: * -> *) a.
(Monad m, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods)) =>
Proxy mods
-> m (RequiredArgument mods a)
-> (Text -> m (RequiredArgument mods a))
-> Maybe (Either Text a)
-> m (RequiredArgument mods a)
unfoldRequiredArgument Proxy mods
_ m (RequiredArgument mods a)
errReq Text -> m (RequiredArgument mods a)
errSt Maybe (Either Text a)
mex =
    case (forall (b :: Bool). SBoolI b => SBool b
sbool :: SBool (FoldRequired mods), Maybe (Either Text a)
mex) of
        (SBool (FoldRequired mods)
STrue, Maybe (Either Text a)
Nothing)  -> m (RequiredArgument mods a)
errReq
        (SBool (FoldRequired mods)
SFalse, Maybe (Either Text a)
Nothing) -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
        (SBool (FoldRequired mods)
STrue, Just Either Text a
ex)  -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Text -> m (RequiredArgument mods a)
errSt forall (m :: * -> *) a. Monad m => a -> m a
return Either Text a
ex
        (SBool (FoldRequired mods)
SFalse, Just Either Text a
ex) -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Text -> m (RequiredArgument mods a)
errSt (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just) Either Text a
ex
type RequestArgument mods a =
    If (FoldRequired mods)
       (If (FoldLenient mods) (Either Text a) a)
       (Maybe (If (FoldLenient mods) (Either Text a) a))
unfoldRequestArgument
    :: forall mods m a. (Monad m, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods))
    => Proxy mods
    -> m (RequestArgument mods a)            
    -> (Text -> m (RequestArgument mods a))  
    -> Maybe (Either Text a)                 
    -> m (RequestArgument mods a)
unfoldRequestArgument :: forall (mods :: [*]) (m :: * -> *) a.
(Monad m, SBoolI (FoldRequired mods), SBoolI (FoldLenient mods)) =>
Proxy mods
-> m (RequestArgument mods a)
-> (Text -> m (RequestArgument mods a))
-> Maybe (Either Text a)
-> m (RequestArgument mods a)
unfoldRequestArgument Proxy mods
_ m (RequestArgument mods a)
errReq Text -> m (RequestArgument mods a)
errSt Maybe (Either Text a)
mex =
    case (forall (b :: Bool). SBoolI b => SBool b
sbool :: SBool (FoldRequired mods), Maybe (Either Text a)
mex, forall (b :: Bool). SBoolI b => SBool b
sbool :: SBool (FoldLenient mods)) of
        (SBool (FoldRequired mods)
STrue,  Maybe (Either Text a)
Nothing, SBool (FoldLenient mods)
_)      -> m (RequestArgument mods a)
errReq
        (SBool (FoldRequired mods)
SFalse, Maybe (Either Text a)
Nothing, SBool (FoldLenient mods)
_)      -> forall (m :: * -> *) a. Monad m => a -> m a
return forall a. Maybe a
Nothing
        (SBool (FoldRequired mods)
STrue,  Just Either Text a
ex, SBool (FoldLenient mods)
STrue)  -> forall (m :: * -> *) a. Monad m => a -> m a
return Either Text a
ex
        (SBool (FoldRequired mods)
STrue,  Just Either Text a
ex, SBool (FoldLenient mods)
SFalse) -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Text -> m (RequestArgument mods a)
errSt forall (m :: * -> *) a. Monad m => a -> m a
return Either Text a
ex
        (SBool (FoldRequired mods)
SFalse, Just Either Text a
ex, SBool (FoldLenient mods)
STrue)  -> forall (m :: * -> *) a. Monad m => a -> m a
return (forall a. a -> Maybe a
Just Either Text a
ex)
        (SBool (FoldRequired mods)
SFalse, Just Either Text a
ex, SBool (FoldLenient mods)
SFalse) -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either Text -> m (RequestArgument mods a)
errSt (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. a -> Maybe a
Just) Either Text a
ex