X-Git-Url: http://git.cielonegro.org/gitweb.cgi?p=Rakka.git;a=blobdiff_plain;f=Rakka%2FUtils.hs;h=717a6068bddfa332b8dddb1edbcd94dc8ed39891;hp=3148c6bf108906112b39ebb81f63132ae8baa158;hb=HEAD;hpb=42f51754dea02201aececaacbf194d714cd58aaf diff --git a/Rakka/Utils.hs b/Rakka/Utils.hs index 3148c6b..717a606 100644 --- a/Rakka/Utils.hs +++ b/Rakka/Utils.hs @@ -16,18 +16,24 @@ module Rakka.Utils , mkQueryString ) where -import qualified Codec.Binary.UTF8.String as UTF8 -import Control.Arrow -import Control.Arrow.ArrowList -import qualified Data.ByteString.Lazy as Lazy (ByteString) -import qualified Data.ByteString.Lazy.Char8 as L8 hiding (ByteString) +import Control.Arrow +import Control.Arrow.ArrowList +import Data.ByteString (ByteString) +import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as C8 +import qualified Data.ByteString.Lazy as LS +import qualified Data.ByteString.Unsafe as BS +import Data.Char import Data.Monoid.Unicode import Data.String -import Magic -import Network.HTTP.Lucu -import Network.URI +import Data.Text (Text) +import Data.Text.Encoding +import Magic +import Network.HTTP.Lucu +import Network.URI +import Numeric import Prelude.Unicode -import System.IO.Unsafe +import System.IO.Unsafe yesOrNo ∷ Bool → String yesOrNo True = "yes" @@ -38,57 +44,90 @@ trueOrFalse True = "true" trueOrFalse False = "false" parseYesOrNo ∷ (Eq s, Show s, IsString s, ArrowChoice (⇝)) ⇒ s ⇝ Bool -parseYesOrNo - = proc str → - case str of - _ | str ≡ "yes" → returnA ⤙ True - | str ≡ "no" → returnA ⤙ False - | otherwise → returnA ⤙ error ("Expected yes or no: " ⊕ show str) +parseYesOrNo = arr f + where + f "yes" = True + f "no" = False + f str = error ("Expected yes or no: " ⊕ show str) -maybeA :: (ArrowList a, ArrowChoice a) => a b c -> a b (Maybe c) +maybeA ∷ (ArrowList a, ArrowChoice a) ⇒ a b c → a b (Maybe c) maybeA a = listA a >>> - proc xs -> case xs of - [] -> returnA -< Nothing - (x:_) -> returnA -< Just x - + proc xs → case xs of + [] → returnA ⤙ Nothing + (x:_) → returnA ⤙ Just x -deleteIfEmpty :: (ArrowList a, ArrowChoice a) => a String String +deleteIfEmpty ∷ (ArrowList a, ArrowChoice a) ⇒ a String String deleteIfEmpty - = proc str -> do case str of - "" -> none -< () - _ -> returnA -< str - + = proc str → do case str of + "" → none ⤙ () + _ → returnA ⤙ str -chomp :: String -> String -chomp = reverse . snd . break (/= '\n') . reverse +chomp ∷ String → String +{-# INLINE chomp #-} +chomp = reverse . snd . break (≢ '\n') . reverse - -guessMIMEType :: Lazy.ByteString -> MIMEType -guessMIMEType = read . unsafePerformIO . magicString magic . L8.unpack +guessMIMEType ∷ LS.ByteString → MIMEType +{-# INLINEABLE guessMIMEType #-} +guessMIMEType = read + ∘ unsafePerformIO + ∘ flip BS.unsafeUseAsCStringLen (magicCString magic) + ∘ BS.concat + ∘ LS.toChunks where - magic :: Magic + magic ∷ Magic + {-# NOINLINE magic #-} magic = unsafePerformIO - $ do m <- magicOpen [MagicMime] + $ do m ← magicOpen [MagicMime] magicLoadDefault m return m - -isSafeChar :: Char -> Bool +isSafeChar ∷ Char → Bool +{-# INLINEABLE isSafeChar #-} isSafeChar c - | c == '/' = True - | isReserved c = False - | c > ' ' && c <= '~' = True - | otherwise = False + | c ≡ '/' = True + | isReserved c = False + | c > ' ' ∧ c ≤ '~' = True + | otherwise = False +mkQueryString ∷ [(Text, Text)] → ByteString +{-# INLINEABLE mkQueryString #-} +mkQueryString = BS.intercalate (C8.singleton ';') ∘ map encodePair + where + encodePair ∷ (Text, Text) → ByteString + {-# INLINE encodePair #-} + encodePair (k, v) + = BS.intercalate (C8.singleton '=') [encodeText k, encodeText v] + + encodeText ∷ Text → ByteString + {-# INLINE encodeText #-} + encodeText = toURLEncoded ∘ encodeUtf8 -mkQueryString :: [(String, String)] -> String -mkQueryString [] = "" -mkQueryString ((k, v) : xs) = encode k ++ "=" ++ encode v ++ - if xs == [] then - "" - else - ';' : mkQueryString(xs) +toURLEncoded ∷ ByteString → ByteString +{-# INLINEABLE toURLEncoded #-} +toURLEncoded = C8.concatMap go where - encode :: String -> String - encode = escapeURIString isSafeChar . UTF8.encodeString \ No newline at end of file + go ∷ Char → ByteString + {-# INLINE go #-} + go c | c ≡ ' ' = C8.singleton '+' + | isReserved c = urlEncode c + | isUnreserved c = C8.singleton c + | otherwise = urlEncode c + + urlEncode ∷ Char → ByteString + {-# INLINE urlEncode #-} + urlEncode c = C8.pack ('%':toHex (ord c)) + + toHex ∷ Int → String + {-# INLINE toHex #-} + toHex n + = case showIntAtBase 16 toChrHex n "" of + [] → "00" + [c] → ['0', c] + cs → cs + + toChrHex ∷ Int → Char + {-# INLINE toChrHex #-} + toChrHex d + | d < 10 = chr (ord '0' + fromIntegral d ) + | otherwise = chr (ord 'A' + fromIntegral (d-10))