, joinWith
, quoteStr
, parseWWWFormURLEncoded
+ , splitPathInfo
+ , show3
)
where
+import Blaze.ByteString.Builder.ByteString as B
+import Blaze.Text.Int as BT
import Control.Monad
import Data.Ascii (Ascii, AsciiBuilder)
import qualified Data.Ascii as A
+import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import Data.List hiding (last)
import Data.Monoid.Unicode
+import Data.Text (Text)
+import Data.Text.Encoding as T
import Network.URI
import Prelude hiding (last)
import Prelude.Unicode
-- |> joinWith ":" ["ab", "c", "def"]
-- > ==> "ab:c:def"
-joinWith ∷ Ascii → [Ascii] → AsciiBuilder
+joinWith ∷ Ascii → [AsciiBuilder] → AsciiBuilder
{-# INLINEABLE joinWith #-}
joinWith sep = flip go (∅)
where
- go ∷ [Ascii] → A.AsciiBuilder → A.AsciiBuilder
+ go ∷ [AsciiBuilder] → AsciiBuilder → AsciiBuilder
{-# INLINE go #-}
go [] ab = ab
- go (x:[]) ab = ab ⊕ A.toAsciiBuilder x
- go (x:xs) ab = go xs ( ab ⊕
- A.toAsciiBuilder sep ⊕
- A.toAsciiBuilder x )
+ go (x:[]) ab = ab ⊕ x
+ go (x:xs) ab = go xs (ab ⊕ A.toAsciiBuilder sep ⊕ x)
-- |> quoteStr "abc"
-- > ==> "\"abc\""
-- |> parseWWWFormURLEncoded "aaa=bbb&ccc=ddd"
-- > ==> [("aaa", "bbb"), ("ccc", "ddd")]
-parseWWWFormURLEncoded ∷ String → [(String, String)]
+parseWWWFormURLEncoded ∷ Ascii → [(ByteString, ByteString)]
parseWWWFormURLEncoded src
- | src == "" = []
- | otherwise = do pairStr <- splitBy (\ c → c == ';' || c == '&') src
- let (key, value) = break (== '=') pairStr
- return ( unEscapeString key
- , unEscapeString $ case value of
- ('=':val) → val
- val → val
+ -- THINKME: We could gain some performance by using attoparsec
+ -- here.
+ | src ≡ "" = []
+ | otherwise = do pairStr ← splitBy (\ c → c ≡ ';' ∨ c ≡ '&') (A.toString src)
+ let (key, value) = break (≡ '=') pairStr
+ return ( unescape key
+ , unescape $ case value of
+ ('=':val) → val
+ val → val
)
+ where
+ unescape ∷ String → ByteString
+ unescape = BS.pack ∘ unEscapeString ∘ map plusToSpace
+
+ plusToSpace ∷ Char → Char
+ plusToSpace '+' = ' '
+ plusToSpace c = c
+
+-- |> splitPathInfo "http://example.com/foo/bar"
+-- > ==> ["foo", "bar"]
+splitPathInfo ∷ URI → [Text]
+splitPathInfo uri
+ = let reqPathStr = uriPath uri
+ reqPath = [unEscapeString x | x ← splitBy (≡ '/') reqPathStr, (¬) (null x)]
+ in
+ map (T.decodeUtf8 ∘ BS.pack) reqPath
+
+-- |> show3 5
+-- > ==> "005"
+show3 ∷ Integral n ⇒ n → AsciiBuilder
+{-# INLINEABLE show3 #-}
+show3 = A.unsafeFromBuilder ∘ go
+ where
+ go i | i ≥ 0 ∧ i < 10 = B.fromByteString "00" ⊕ BT.digit i
+ | i ≥ 0 ∧ i < 100 = B.fromByteString "0" ⊕ BT.integral i
+ | i ≥ 0 ∧ i < 1000 = BT.integral i
+ | otherwise = error ("show3: the integer i must satisfy 0 <= i < 1000: " ⧺ show i)