minion-0.1.0.0: src/Web/Minion/Args/Internal.hs
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilyDependencies #-}
{-# OPTIONS_GHC -Wno-deferred-out-of-scope-variables #-}
module Web.Minion.Args.Internal where
import Data.Functor (($>))
import Data.Kind (Type)
import Data.Void (Void)
import Web.Minion.Request (IsRequest (..))
data (a :: Type) :+ (b :: Type)
infixl 9 :+
data HList ts where
HNil :: HList '[]
(:#) :: t -> HList ts -> HList (t ': ts)
-- | Reversed HList
data RHList ts where
RHNil :: RHList Void
(:#!) :: t -> RHList ts -> RHList (ts :+ t)
type family MapElem ts t t' where
MapElem (ts :+ t) t t' = ts :+ t'
MapElem (ts :+ x) t t' = MapElem ts t t' :+ x
MapElem Void t t' = Void
infixr 1 :#
infixr 1 :#!
deriving instance Show (RHList Void)
deriving instance (Show (RHList as), Show a) => Show (RHList (as :+ a))
deriving instance Show (HList '[])
deriving instance (Show (HList as), Show a) => Show (HList (a ': as))
type family RevToList ts where
RevToList Void = '[]
RevToList (as :+ a) = a ': RevToList as
class RHListToHList (ts :: Type) where
type HListTypes ts :: [Type]
revHListToList :: RHList ts -> HList (HListTypes ts)
instance RHListToHList Void where
type HListTypes Void = '[]
revHListToList _ = HNil
instance (RHListToHList as) => RHListToHList (as :+ a) where
type HListTypes (as :+ a) = a ': HListTypes as
revHListToList (a :#! as) = a :# revHListToList as
class GetByType t ts where
getByType :: HList ts -> t
instance (GetByType t ts) => GetByType t (x ': ts) where
getByType (_ :# as) = getByType @t @ts as
instance {-# OVERLAPPING #-} GetByType t (t ': ts) where
getByType (a :# _) = a
class Reverse' (l1 :: [Type]) (l2 :: [Type]) (l3 :: [Type]) | l1 l2 -> l3 where
reverse' :: HList l1 -> HList l2 -> HList l3
instance Reverse' '[] l2 l2 where
reverse' _ l = l
instance (Reverse' l (x ': l') z) => Reverse' (x ': l) l' z where
reverse' (x :# l) l' = reverse' l (x :# l')
class Reverse xs sx | xs -> sx, sx -> xs where
reverseHList :: HList xs -> HList sx
instance
( Reverse' xs '[] sx
, Reverse' sx '[] xs
) =>
Reverse xs sx
where
reverseHList l = reverse' l HNil
data Lenient e
data Strict
data Required
data Optional
class IsRequired a where
isRequired :: Bool
instance IsRequired Required where
isRequired = True
instance IsRequired Optional where
isRequired = False
class IsLenient a where
isLenient :: Bool
instance IsLenient (Lenient a) where
isLenient = True
instance IsLenient Strict where
isLenient = False
type family Arg presence parsing a where
Arg Required (Lenient e) a = (Either e a)
Arg Required Strict a = a
Arg Optional (Lenient e) a = (Maybe (Either e a))
Arg Optional Strict a = (Maybe a)
newtype WithHeader presence parsing m a = WithHeader (m (Arg presence parsing a))
newtype WithQueryParam presence parsing m a = WithQueryParam (m (Arg presence parsing a))
newtype WithPiece a = WithPiece a
newtype WithPieces a = WithPieces [a]
newtype WithReq m r = WithReq (m r)
newtype Hide a = Hide a
class Hidden m a where
runHidden :: Hide a -> m ()
instance (Monad m) => Hidden m (WithHeader a b m a) where
runHidden (Hide (WithHeader a)) = a $> ()
instance (Monad m) => Hidden m (WithQueryParam a b m a) where
runHidden (Hide (WithQueryParam a)) = a $> ()
instance (Monad m) => Hidden m (WithPiece a) where
runHidden (Hide (WithPiece _)) = pure ()
instance (Monad m) => Hidden m (WithPieces a) where
runHidden (Hide (WithPieces _)) = pure ()
instance (Monad m) => Hidden m (WithReq m a) where
runHidden (Hide (WithReq a)) = a $> ()
instance (Hidden m a) => Hidden m (Hide a) where
runHidden (Hide a) = runHidden a
class FunArgs (ts :: [Type]) where
type ts ~> r :: Type
apply :: (ts ~> r) -> HList ts -> r
type HandleArgs ts st m =
( FunArgs (DelayedArgs st)
, RHListToHList ts
, Reverse (HListTypes ts) st
, RunDelayed st m
, Monad m
)
instance FunArgs '[] where
type '[] ~> r = r
{-# INLINE apply #-}
apply a _ = a
instance (FunArgs as) => FunArgs (a ': as) where
type (a ': as) ~> r = a -> as ~> r
{-# INLINE apply #-}
apply a (x :# xs) = apply (a x) xs
class (Monad m) => RunDelayed ts m where
type DelayedArgs ts :: [Type]
runDelayed :: HList ts -> m (HList (DelayedArgs ts))
instance (Monad m) => RunDelayed '[] m where
type DelayedArgs '[] = '[]
{-# INLINE runDelayed #-}
runDelayed HNil = pure HNil
instance (RunDelayed as m) => RunDelayed (WithHeader required lenient m a ': as) m where
type DelayedArgs (WithHeader required lenient m a ': as) = Arg required lenient a ': DelayedArgs as
{-# INLINE runDelayed #-}
runDelayed (WithHeader hIO :# as) = do
h <- hIO
rest <- runDelayed as
pure $ h :# rest
instance (RunDelayed as m, IsRequest r) => RunDelayed (WithReq m r ': as) m where
type DelayedArgs (WithReq m r ': as) = RequestValue r ': DelayedArgs as
{-# INLINE runDelayed #-}
runDelayed (WithReq hIO :# as) = do
h <- hIO
rest <- runDelayed as
pure $ getRequestValue h :# rest
instance (RunDelayed as m) => RunDelayed (WithQueryParam required lenient m a ': as) m where
type DelayedArgs (WithQueryParam required lenient m a ': as) = Arg required lenient a ': DelayedArgs as
{-# INLINE runDelayed #-}
runDelayed (WithQueryParam a :# as) = do
a' <- a
rest <- runDelayed as
pure $ a' :# rest
instance (RunDelayed as m) => RunDelayed (WithPiece a ': as) m where
type DelayedArgs (WithPiece a ': as) = a ': DelayedArgs as
{-# INLINE runDelayed #-}
runDelayed (WithPiece a :# as) = do
rest <- runDelayed as
pure $ a :# rest
instance (RunDelayed as m) => RunDelayed (WithPieces a ': as) m where
type DelayedArgs (WithPieces a ': as) = [a] ': DelayedArgs as
{-# INLINE runDelayed #-}
runDelayed (WithPieces a :# as) = do
rest <- runDelayed as
pure $ a :# rest
instance (RunDelayed as m, Hidden m a) => RunDelayed (Hide a ': as) m where
type DelayedArgs (Hide a ': as) = DelayedArgs as
{-# INLINE runDelayed #-}
runDelayed (a :# as) = runHidden a >> runDelayed as