packages feed

dormouse-uri-0.1.0.0: src/Dormouse/Uri/Encode.hs

{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}

module Dormouse.Uri.Encode
  ( encodeQuery
  , encodePath
  , encodeUnless
  ) where

import Data.Char (chr)
import Data.Word (Word8)
import qualified Data.ByteString as B
import qualified Data.Text as T
import qualified Data.Text.Encoding as E
import Dormouse.Uri.Types
import Dormouse.Uri.RFC3986

-- | Percent encode a word8 as an ascii 'Bytestring'
percentEncode :: Word8 -> B.ByteString
percentEncode w = 
  let h = w `div` 16
      l = w `mod` 16 in
  B.pack [37, hex h, hex l]
  where 
    hex x
     | x < 10    = 48+x
     | otherwise = 55+x

-- | Percent encode all chars in the supplied text except for those which satsify the supplied predicate
encodeUnless :: (Char -> Bool)  -> T.Text -> B.ByteString
encodeUnless isAllowedChar = B.concatMap pEncodeQuery . E.encodeUtf8
  where
    pEncodeQuery :: Word8 -> B.ByteString
    pEncodeQuery c
      | isAllowedChar (chr $ fromEnum c) = B.singleton c
      | otherwise                         = percentEncode c

-- | Generate an ascii `Bytestring` from a supplied Query by percent encoding all of the invalid octets
encodeQuery :: Query -> B.ByteString
encodeQuery = B.append "?" . encodeUnless isQueryChar . unQuery

-- | Generate an ascii `Bytestring` from a supplied Path by percent encoding all of the invalid octets
encodePath :: Path 'Absolute -> B.ByteString
encodePath =  B.append "/" . B.intercalate "/" . fmap (encodeUnless isPathChar . unPathSegment) . unPath