module Hpack.Utf8 (
  encodeUtf8
, readFile
, writeFile
, putStr
, hPutStr
, hPutStrLn
) where

import           Prelude hiding (readFile, writeFile, putStr)

import qualified Data.Text as T
import qualified Data.Text.Encoding as Encoding
import           Data.Text.Encoding.Error (lenientDecode)
import qualified Data.ByteString as B
import           System.IO (Handle, stdout, IOMode(..), withFile, Newline(..), nativeNewline)

encodeUtf8 :: String -> B.ByteString
encodeUtf8 :: String -> ByteString
encodeUtf8 = Text -> ByteString
Encoding.encodeUtf8 (Text -> ByteString) -> (String -> Text) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

decodeUtf8 :: B.ByteString -> String
decodeUtf8 :: ByteString -> String
decodeUtf8 = Text -> String
T.unpack (Text -> String) -> (ByteString -> Text) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. OnDecodeError -> ByteString -> Text
Encoding.decodeUtf8With OnDecodeError
lenientDecode

encodeText :: String -> B.ByteString
encodeText :: String -> ByteString
encodeText = String -> ByteString
encodeUtf8 (String -> ByteString)
-> (String -> String) -> String -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> String
encodeNewlines

decodeText :: B.ByteString -> String
decodeText :: ByteString -> String
decodeText = String -> String
decodeNewlines (String -> String)
-> (ByteString -> String) -> ByteString -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
decodeUtf8

encodeNewlines :: String -> String
encodeNewlines :: String -> String
encodeNewlines = case Newline
nativeNewline of
  Newline
LF -> String -> String
forall a. a -> a
id
  Newline
CRLF -> String -> String
go
    where
      go :: String -> String
go String
xs = case String
xs of
        Char
'\n' : String
ys -> Char
'\r' Char -> String -> String
forall a. a -> [a] -> [a]
: Char
'\n' Char -> String -> String
forall a. a -> [a] -> [a]
: String
ys
        Char
y : String
ys -> Char
y Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
go String
ys
        [] -> []

decodeNewlines :: String -> String
decodeNewlines :: String -> String
decodeNewlines = String -> String
go
  where
    go :: String -> String
go String
xs = case String
xs of
      Char
'\r' : Char
'\n' : String
ys -> Char
'\n' Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
go String
ys
      Char
y : String
ys -> Char
y Char -> String -> String
forall a. a -> [a] -> [a]
: String -> String
go String
ys
      [] -> []

readFile :: FilePath -> IO String
readFile :: String -> IO String
readFile = (ByteString -> String) -> IO ByteString -> IO String
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString -> String
decodeText (IO ByteString -> IO String)
-> (String -> IO ByteString) -> String -> IO String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> IO ByteString
B.readFile

writeFile :: FilePath -> String -> IO ()
writeFile :: String -> String -> IO ()
writeFile String
name String
xs = String -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. String -> IOMode -> (Handle -> IO r) -> IO r
withFile String
name IOMode
WriteMode (Handle -> String -> IO ()
`hPutStr` String
xs)

putStr :: String -> IO ()
putStr :: String -> IO ()
putStr = Handle -> String -> IO ()
hPutStr Handle
stdout

hPutStrLn :: Handle -> String -> IO ()
hPutStrLn :: Handle -> String -> IO ()
hPutStrLn Handle
h String
xs = Handle -> String -> IO ()
hPutStr Handle
h String
xs IO () -> IO () -> IO ()
forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> Handle -> String -> IO ()
hPutStr Handle
h String
"\n"

hPutStr :: Handle -> String -> IO ()
hPutStr :: Handle -> String -> IO ()
hPutStr Handle
h = Handle -> ByteString -> IO ()
B.hPutStr Handle
h (ByteString -> IO ()) -> (String -> ByteString) -> String -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
encodeText