{-# language PolyKinds, TypeOperators, DeriveGeneric, TypeSynonymInstances, FlexibleContexts, FlexibleInstances, ScopedTypeVariables #-} module Web.Routes.Generics where import Data.Text (Text, pack, toLower) import GHC.Generics import Text.ParserCombinators.Parsec.Prim import Text.ParserCombinators.Parsec.Combinator import Web.Routes.PathInfo (PathInfo(fromPathSegments, toPathSegments), URLParser, segment) class GToURL f where gtoPathSegments :: f a -> [Text] gfromPathSegments :: URLParser (f a) instance GToURL U1 where gtoPathSegments U1 = [] gfromPathSegments = eof >> pure U1 instance forall c f. (Constructor c, GToURL f) => GToURL (C1 c f) where gtoPathSegments m@(M1 x) = (toLower $ pack $ conName m) : gtoPathSegments x gfromPathSegments = let constr = undefined :: C1 c f r in do segment (toLower $ pack $ conName constr) <|> segment (pack $ conName constr) M1 <$> gfromPathSegments instance (GToURL f, GToURL g) => GToURL (f :+: g) where gtoPathSegments (L1 x) = gtoPathSegments x gtoPathSegments (R1 x) = gtoPathSegments x gfromPathSegments = try (L1 <$> gfromPathSegments) <|> (R1 <$> gfromPathSegments) instance (GToURL f, GToURL g) => GToURL (f :*: g) where gtoPathSegments (x :*: y) = gtoPathSegments x ++ gtoPathSegments y gfromPathSegments = do x <- gfromPathSegments y <- gfromPathSegments pure (x :*: y) instance (GToURL f) => GToURL (D1 c f) where gtoPathSegments m@(M1 x) = gtoPathSegments x gfromPathSegments = M1 <$> gfromPathSegments instance (PathInfo a) => GToURL (K1 i a) where gtoPathSegments (K1 a) = toPathSegments a gfromPathSegments = K1 <$> fromPathSegments instance (GToURL f) => GToURL (S1 c f) where gtoPathSegments (M1 f) = gtoPathSegments f gfromPathSegments = M1 <$> gfromPathSegments