packages feed

imm-2.0.0.0: src/lib/URI/ByteString/Extended.hs

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE GADTs                     #-}
{-# LANGUAGE RankNTypes                #-}
{-# LANGUAGE StandaloneDeriving        #-}
{-# LANGUAGE TypeOperators             #-}
module URI.ByteString.Extended (module URI.ByteString.Extended, module URI.ByteString) where

import           Data.Aeson.Extended
import           Data.Type.Equality
import           Imm.Pretty
import           URI.ByteString


data AnyURI = forall a . AnyURI (URIRef a)

deriving instance Show AnyURI
instance Eq AnyURI where
  (AnyURI a) == (AnyURI b) = case sameURIType a b of
    Just Refl -> a == b
    _         -> False

instance Ord AnyURI where
  compare (AnyURI a) (AnyURI b) = case (a, b) of
    (URI{}, URI{})                 -> compare a b
    (RelativeRef{}, RelativeRef{}) -> compare a b
    (URI{}, RelativeRef{})         -> LT
    (RelativeRef{}, URI{})         -> GT

instance Pretty AnyURI where
  pretty (AnyURI a@URI{})         = prettyURI a
  pretty (AnyURI a@RelativeRef{}) = prettyURI a

instance ToJSON AnyURI where
  toJSON (AnyURI a@URI{})         = toJSON $ String $ decodeUtf8 $ serializeURIRef' a
  toJSON (AnyURI a@RelativeRef{}) = toJSON $ String $ decodeUtf8 $ serializeURIRef' a

instance FromJSON AnyURI where
  parseJSON = withText "URI" $ \s ->
    let bytes = encodeUtf8 s
        uri = parseURI laxURIParserOptions bytes
        relativeRef = parseRelativeRef laxURIParserOptions bytes
    in either (const $ fail "Invalid URI") pure $ (AnyURI <$> uri) <> (AnyURI <$> relativeRef)


sameURIType :: URIRef a1 -> URIRef a2 -> Maybe (URIRef a1 :~: URIRef a2)
sameURIType a b = case (a, b) of
  (URI{}, URI{})                 -> Just Refl
  (RelativeRef{}, RelativeRef{}) -> Just Refl
  _                              -> Nothing

withAnyURI :: (forall a . URIRef a -> b) -> AnyURI -> b
withAnyURI f (AnyURI a) = f a

toAbsoluteURI :: Scheme -> AnyURI -> URI
toAbsoluteURI scheme (AnyURI a) = toAbsolute scheme a