{-#LANGUAGE MultiParamTypeClasses #-} {-#LANGUAGE FlexibleInstances #-} {-#LANGUAGE FlexibleContexts #-} {-#LANGUAGE RankNTypes #-} {-#LANGUAGE FunctionalDependencies #-} {-#LANGUAGE OverloadedStrings #-} module Web.Sprinkles.Prelude ( module P , LText , LByteString , Packable (..) , MapLike (..) , SetLike (..) , TextLike (..) , ListLike (..) , StrictnessConvert (..) , Encode (..) , splitElem , readMay , Cased (..) , throwM , FileIO (..) , hPut , (++) , concat , empty , getArgs , getEnv , lookupEnv , sha1, sha256, sha512 ) where import Prelude as P hiding ( unwords , words , lookup , length , take , drop , takeWhile , dropWhile , null , tail , break , filter , unlines , putStr , putStrLn , hPutStr , hPutStrLn , readFile , writeFile , getContents , hGetContents , (++) , concat , empty , sha1 ) import Data.Text as P (Text) import Data.ByteString as P (ByteString) import Data.Hashable (Hashable) import Data.Map as P (Map) import Data.HashMap.Strict as P (HashMap) import Data.Set as P (Set) import Data.HashSet as P (HashSet) import Data.Hashable as P (Hashable (..)) import Data.Maybe as P (fromMaybe, catMaybes, isNothing, isJust) import Data.String as P (IsString (..)) import Data.Vector as P (Vector) import Data.List as P (sortOn) import Data.Word as P (Word8, Word16, Word32, Word64, Word) import Data.Int as P (Int8, Int16, Int32, Int64) import Control.Monad as P import Data.Semigroup as P hiding (getAll, All) import Data.Monoid as P hiding (getFirst, getLast, First, Last, getAll, All) import Control.Monad.IO.Class as P import Control.Exception as P (bracket, bracket_, throw, catch) import Control.Applicative as P hiding (empty) import Data.IORef as P import Control.Concurrent as P import Control.Concurrent.STM as P import Control.Concurrent.Chan as P import Control.Concurrent.MVar as P import Control.Exception as P hiding (throw) import Data.Time as P (UTCTime (..), getCurrentTime) import GHC.Generics as P (Generic) import System.IO as P (stdin, stdout, stderr, Handle) import System.IO.Error as P import System.FilePath as P import Text.Printf as P (printf) import Control.Monad.Identity as P import qualified Prelude import qualified Data.List as List import qualified Data.List.Split as List (splitWhen, splitOn) import qualified Data.Map as Map import qualified Data.Set as Set import qualified Data.HashMap.Strict as HashMap import qualified Data.HashSet as HashSet import qualified Data.Text.Lazy as LText import qualified Data.Text.Lazy.IO as LText import qualified Data.Text.Lazy.Encoding as LText import qualified Data.Text as Text import qualified Data.Text.IO as Text import qualified Data.Text.Encoding as Text import qualified Data.Char as Char (toLower, toUpper) import qualified Data.ByteString.Lazy as LBS import qualified Data.ByteString as BS import qualified Data.Vector as Vector import qualified System.IO import qualified System.Environment as Env import qualified Data.Digest.Pure.SHA as SHA import Text.Read (readMaybe) import Control.Exception (throw) readMay :: (Read a, Packable t [Char]) => t -> Maybe a readMay = readMaybe . unpack throwM :: (Exception e, Monad m) => e -> m a throwM = throw type LText = LText.Text type LByteString = LBS.ByteString (++) :: Semigroup m => m -> m -> m (++) = (<>) concat :: Monoid m => [m] -> m concat = mconcat empty :: Monoid m => m empty = mempty class Packable t s | t -> s where pack :: s -> t unpack :: t -> s instance Packable Text [Char] where pack = Text.pack unpack = Text.unpack instance Packable LText [Char] where pack = LText.pack unpack = LText.unpack instance Packable [a] [a] where pack = id unpack = id class MapLike m k v | m -> k, m -> v where mapFromList :: [(k,v)] -> m mapToList :: m -> [(k,v)] lookup :: k -> m -> Maybe v insertMap :: k -> v -> m -> m deleteMap :: k -> m -> m keys :: m -> [k] instance (Eq k, Hashable k) => MapLike (HashMap k v) k v where mapFromList = HashMap.fromList mapToList = HashMap.toList lookup = HashMap.lookup insertMap = HashMap.insert deleteMap = HashMap.delete keys = HashMap.keys instance (Ord k) => MapLike (Map k v) k v where mapFromList = Map.fromList mapToList = Map.toList lookup = Map.lookup insertMap = Map.insert deleteMap = Map.delete keys = Map.keys instance (Ord k, Eq k) => MapLike [(k, v)] k v where mapFromList = id mapToList = id lookup = List.lookup insertMap = \k v -> ((k,v):) deleteMap = \k -> List.filter ((/= k) . fst) keys = map fst class SetLike l c | l -> c where setFromList :: [c] -> l instance Ord a => SetLike (Set a) a where setFromList = Set.fromList class ListLike l c | l -> c where length :: l -> Int take :: Int -> l -> l drop :: Int -> l -> l takeWhile :: (c -> Bool) -> l -> l dropWhile :: (c -> Bool) -> l -> l break :: (c -> Bool) -> l -> (l, l) splitWhen :: (c -> Bool) -> l -> [l] splitSeq :: Eq c => l -> l -> [l] splitSeq = \sep lst -> map fromList $ List.splitOn (toList sep) (toList lst) toList :: l -> [c] fromList :: [c] -> l null :: l -> Bool headMay :: l -> Maybe c headMay = \xs -> case toList xs of (x:_) -> Just x _ -> Nothing tail :: l -> l tail = drop 1 intercalate :: l -> [l] -> l filter :: (c -> Bool) -> l -> l filter = \p -> fromList . List.filter p . toList splitElem :: (Eq c, ListLike l c) => c -> l -> [l] splitElem c = splitWhen (== c) instance ListLike [a] a where length = List.length take = List.take drop = List.drop takeWhile = List.takeWhile dropWhile = List.dropWhile break = List.break splitWhen = List.splitWhen toList = id fromList = id null = List.null intercalate = List.intercalate filter = List.filter instance ListLike (Vector a) a where length = Vector.length take = Vector.take drop = Vector.drop takeWhile = Vector.takeWhile dropWhile = Vector.dropWhile break = Vector.break splitWhen = splitVectorWhen toList = Vector.toList fromList = Vector.fromList null = Vector.null intercalate = mintercalate filter = Vector.filter mintercalate :: Monoid m => m -> [m] -> m mintercalate _ [] = mempty mintercalate _ [x] = x mintercalate sep (x:xs) = x <> sep <> mintercalate sep xs splitVectorWhen :: (a -> Bool) -> Vector a -> [Vector a] splitVectorWhen p v = case Vector.findIndex p v of Nothing -> [v] Just index -> let (current, remainder) = Vector.splitAt index v in current : splitVectorWhen p remainder instance ListLike Text Char where length = Text.length take = Text.take drop = Text.drop takeWhile = Text.takeWhile dropWhile = Text.dropWhile break = Text.break splitWhen = Text.split toList = Text.unpack fromList = Text.pack null = Text.null intercalate = Text.intercalate filter = Text.filter instance ListLike LText Char where length = fromIntegral . LText.length take = LText.take . fromIntegral drop = LText.drop . fromIntegral takeWhile = LText.takeWhile dropWhile = LText.dropWhile break = LText.break splitWhen = LText.split toList = LText.unpack fromList = LText.pack null = LText.null intercalate = LText.intercalate filter = LText.filter instance ListLike ByteString Word8 where length = BS.length take = BS.take drop = BS.drop takeWhile = BS.takeWhile dropWhile = BS.dropWhile break = BS.break splitWhen = BS.splitWith toList = BS.unpack fromList = BS.pack null = BS.null intercalate = BS.intercalate filter = BS.filter instance ListLike LByteString Word8 where length = fromIntegral . LBS.length take = LBS.take . fromIntegral drop = LBS.drop . fromIntegral takeWhile = LBS.takeWhile dropWhile = LBS.dropWhile break = LBS.break splitWhen = LBS.splitWith toList = LBS.unpack fromList = LBS.pack null = LBS.null intercalate = LBS.intercalate filter = LBS.filter class (Monoid t, Semigroup t, IsString t) => TextLike t where unwords :: [t] -> t words :: t -> [t] isPrefixOf :: t -> t -> Bool isSuffixOf :: t -> t -> Bool tshow :: forall a. Show a => a -> t unlines :: [t] -> t unlines = mintercalate "\n" instance TextLike [Char] where unwords = Prelude.unwords words = Prelude.words isPrefixOf = List.isPrefixOf isSuffixOf = List.isSuffixOf tshow = show instance TextLike Text where unwords = Text.unwords words = Text.words isPrefixOf = Text.isPrefixOf isSuffixOf = Text.isSuffixOf tshow = pack . show unlines = Text.unlines instance TextLike LText where unwords = LText.unwords words = LText.words isPrefixOf = LText.isPrefixOf isSuffixOf = LText.isSuffixOf tshow = pack . show unlines = LText.unlines class Encode decoded encoded | decoded -> encoded, encoded -> decoded where encodeUtf8 :: decoded -> encoded decodeUtf8 :: encoded -> decoded instance Encode Text ByteString where encodeUtf8 = Text.encodeUtf8 decodeUtf8 = Text.decodeUtf8 instance Encode LText LByteString where encodeUtf8 = LText.encodeUtf8 decodeUtf8 = LText.decodeUtf8 class StrictnessConvert strict lazy | strict -> lazy, lazy -> strict where toStrict :: lazy -> strict fromStrict :: strict -> lazy instance StrictnessConvert ByteString LByteString where toStrict = LBS.toStrict fromStrict = LBS.fromStrict instance StrictnessConvert Text LText where toStrict = LText.toStrict fromStrict = LText.fromStrict class Cased t where toUpper :: t -> t toLower :: t -> t instance Cased Char where toUpper = Char.toUpper toLower = Char.toLower instance (Functor f, Cased t) => Cased (f t) where toUpper = fmap toUpper toLower = fmap toLower instance Cased Text where toUpper = Text.toUpper toLower = Text.toLower class (Semigroup s, IsString s) => FileIO s where getContents :: IO s readFile :: FilePath -> IO s writeFile :: FilePath -> s -> IO () hGetContents :: Handle -> IO s putStr :: s -> IO () putStrLn :: s -> IO () putStrLn = putStr . (<> "\n") hPutStr :: Handle -> s -> IO () hPutStrLn :: Handle -> s -> IO () hPutStrLn = \h -> hPutStr h . (<> "\n") instance FileIO String where getContents = System.IO.getContents readFile = System.IO.readFile writeFile = System.IO.writeFile hGetContents = System.IO.hGetContents putStr = System.IO.putStr putStrLn = System.IO.putStrLn hPutStr = System.IO.hPutStr hPutStrLn = System.IO.hPutStrLn instance FileIO Text where getContents = Text.getContents readFile = Text.readFile writeFile = Text.writeFile hGetContents = Text.hGetContents putStr = Text.putStr putStrLn = Text.putStrLn hPutStr = Text.hPutStr hPutStrLn = Text.hPutStrLn instance FileIO LText where getContents = LText.getContents readFile = LText.readFile writeFile = LText.writeFile hGetContents = LText.hGetContents putStr = LText.putStr putStrLn = LText.putStrLn hPutStr = LText.hPutStr hPutStrLn = LText.hPutStrLn instance FileIO ByteString where getContents = BS.getContents readFile = BS.readFile writeFile = BS.writeFile hGetContents = BS.hGetContents putStr = BS.putStr hPutStr = BS.hPutStr instance FileIO LByteString where getContents = LBS.getContents readFile = LBS.readFile writeFile = LBS.writeFile hGetContents = LBS.hGetContents putStr = LBS.putStr hPutStr = LBS.hPutStr hPut :: FileIO s => Handle -> s -> IO () hPut = hPutStr getArgs :: (Packable t String) => IO [t] getArgs = map pack <$> Env.getArgs getEnv :: (Packable v String) => String -> IO v getEnv = fmap pack . Env.getEnv lookupEnv :: (Packable v String) => String -> IO (Maybe v) lookupEnv = fmap (fmap pack) . Env.lookupEnv class HashDigest a where digest :: forall t. SHA.Digest t -> a instance HashDigest String where digest = SHA.showDigest instance HashDigest Text where digest = pack . digest instance HashDigest LText where digest = pack . digest instance HashDigest LByteString where digest = SHA.bytestringDigest instance HashDigest ByteString where digest = toStrict . digest instance HashDigest Integer where digest = SHA.integerDigest sha1 :: HashDigest a => LByteString -> a sha1 = digest . SHA.sha1 sha256 :: HashDigest a => LByteString -> a sha256 = digest . SHA.sha1 sha512 :: HashDigest a => LByteString -> a sha512 = digest . SHA.sha1