X-Git-Url: http://git.cielonegro.org/gitweb.cgi?a=blobdiff_plain;f=Rakka%2FUtils.hs;h=e89fee08c381e21c66bdd498556442915a64e047;hb=9932fbe6504e8b812703291e2497a5f010880d3b;hp=9eb667c115971c10d816f0176e8d9bda2b4a1632;hpb=9ff4eb243ae1545c62a5ab2eaf8dcb2f7c40b20d;p=Rakka.git diff --git a/Rakka/Utils.hs b/Rakka/Utils.hs index 9eb667c..e89fee0 100644 --- a/Rakka/Utils.hs +++ b/Rakka/Utils.hs @@ -1,43 +1,133 @@ +{-# LANGUAGE + Arrows + , UnicodeSyntax + #-} module Rakka.Utils ( yesOrNo + , trueOrFalse , parseYesOrNo , maybeA , deleteIfEmpty , chomp + , guessMIMEType + , mkQueryString ) where +import Control.Arrow +import Control.Arrow.ArrowList +import Data.Ascii (Ascii) +import qualified Data.Ascii as A +import qualified Data.ByteString as BS +import qualified Data.ByteString.Char8 as C8 +import qualified Data.ByteString.Unsafe as BS +import qualified Data.ByteString.Lazy as LS +import Data.Char +import qualified Data.Text as T +import Data.Text.Encoding +import Magic +import Network.HTTP.Lucu +import Network.URI +import Numeric +import Prelude.Unicode +import System.IO.Unsafe -import Control.Arrow -import Control.Arrow.ArrowList - - -yesOrNo :: Bool -> String +yesOrNo ∷ Bool → String yesOrNo True = "yes" yesOrNo False = "no" +trueOrFalse ∷ Bool → String +trueOrFalse True = "true" +trueOrFalse False = "false" -parseYesOrNo :: ArrowChoice a => a String Bool +parseYesOrNo ∷ ArrowChoice a ⇒ a String Bool parseYesOrNo - = proc str -> do case str of - "yes" -> returnA -< True - "no" -> returnA -< False - _ -> returnA -< error ("Expected yes or no: " ++ str) + = proc str → do case str of + "yes" → returnA ⤙ True + "no" → returnA ⤙ False + _ → returnA ⤙ error ("Expected yes or no: " ⧺ 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 +{-# INLINE chomp #-} +chomp = reverse . snd . break (≢ '\n') . reverse + +guessMIMEType ∷ LS.ByteString → MIMEType +{-# INLINEABLE guessMIMEType #-} +guessMIMEType = read + ∘ unsafePerformIO + ∘ flip BS.unsafeUseAsCStringLen (magicCString magic) + ∘ BS.concat + ∘ LS.toChunks + where + magic ∷ Magic + {-# NOINLINE magic #-} + magic = unsafePerformIO + $ do m ← magicOpen [MagicMime] + magicLoadDefault m + return m + +{- +isSafeChar ∷ Char → Bool +{-# INLINEABLE isSafeChar #-} +isSafeChar c + | c ≡ '/' = True + | isReserved c = False + | c > ' ' ∧ c ≤ '~' = True + | otherwise = False +-} + +mkQueryString ∷ [(T.Text, T.Text)] → Ascii +{-# INLINEABLE mkQueryString #-} +mkQueryString = A.unsafeFromByteString + ∘ BS.intercalate (C8.singleton ';') + ∘ map encodePair + where + encodePair ∷ (T.Text, T.Text) → BS.ByteString + {-# INLINE encodePair #-} + encodePair (k, v) + = BS.intercalate (C8.singleton '=') [encodeText k, encodeText v] + + encodeText ∷ T.Text → BS.ByteString + {-# INLINE encodeText #-} + encodeText = toURLEncoded ∘ encodeUtf8 + +toURLEncoded ∷ BS.ByteString → BS.ByteString +{-# INLINEABLE toURLEncoded #-} +toURLEncoded = C8.concatMap go + where + go ∷ Char → BS.ByteString + {-# INLINE go #-} + go c | c ≡ ' ' = C8.singleton '+' + | isReserved c = urlEncode c + | isUnreserved c = C8.singleton c + | otherwise = urlEncode c + + urlEncode ∷ Char → BS.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 -chomp :: String -> String -chomp = reverse . snd . break (/= '\n') . reverse + toChrHex ∷ Int → Char + {-# INLINE toChrHex #-} + toChrHex d + | d < 10 = chr (ord '0' + fromIntegral d ) + | otherwise = chr (ord 'A' + fromIntegral (d-10))