module Data.URI.Internal.UserInfo
( UserInfo
, parser
, fromByteString
, toBuilder
)
where
import Blaze.ByteString.Builder (Builder)
import qualified Blaze.ByteString.Builder.ByteString as BB
import Control.Applicative
import Control.Failure
import Codec.URI.PercentEncoding (DelimitedByteString)
import qualified Codec.URI.PercentEncoding as PE
import Data.Attoparsec.Char8
import Data.Data
import Data.Hashable
import Data.Monoid
import Data.Monoid.Unicode
import Data.Semigroup
import Data.String
import Data.URI.Internal
import Data.Vector.Storable.ByteString (ByteString)
import qualified Data.Vector.Storable.ByteString.Char8 as C8
import Data.Vector.Storable.ByteString.Legacy
import Prelude hiding (takeWhile)
import Prelude.Unicode
#if defined(MIN_VERSION_QuickCheck)
import Test.QuickCheck.Arbitrary
#endif
newtype UserInfo = UserInfo { unUserInfo ∷ DelimitedByteString }
deriving ( Eq
, Hashable
, Ord
, Typeable
, Monoid
#if defined(MIN_VERSION_QuickCheck)
, Arbitrary
, CoArbitrary
#endif
)
instance Show UserInfo where
show = C8.unpack ∘ PE.encode ((¬) ∘ isSafeInUserInfo) ∘ unUserInfo
deriving instance IsString UserInfo
instance Semigroup UserInfo where
(<>) = (⊕)
parser ∷ Parser UserInfo
parser = do src ← takeWhile isAllowedInUserInfo
case PE.decode (≡ ':') (fromLegacyByteString src) of
Right dst → pure $ UserInfo dst
Left e → fail $ show (e ∷ PE.DecodeError)
<?>
"userinfo"
isSafeInUserInfo ∷ Char → Bool
isSafeInUserInfo c = isUnreserved c ∨ isSubDelim c
isAllowedInUserInfo ∷ Char → Bool
isAllowedInUserInfo c
= isUnreserved c ∨
isPctEncoded c ∨
isSubDelim c ∨
':' ≡ c
toBuilder ∷ UserInfo → Builder
toBuilder = BB.fromByteString ∘
toLegacyByteString ∘
PE.encode ((¬) ∘ isSafeInUserInfo) ∘
unUserInfo
fromByteString ∷ Failure String f ⇒ ByteString → f UserInfo
fromByteString = either failure return ∘
parseOnly parser ∘
toLegacyByteString