{-# LANGUAGE FlexibleInstances #-}
module Lambdabot.Util.Serial
( Serial(..)
, stdSerial
, mapSerial
, mapPackedSerial
, assocListPackedSerial
, mapListPackedSerial
, readM
, Packable(..)
, readOnly
) where
import Control.Monad.Fail (MonadFail)
import Data.Maybe (mapMaybe)
import Data.Map (Map)
import qualified Data.Map as M
import qualified Data.ByteString.Char8 as P
import Data.ByteString.Char8 (ByteString)
import Data.ByteString.Lazy (fromChunks,toChunks)
import Codec.Compression.GZip
data Serial s = Serial {
Serial s -> s -> Maybe ByteString
serialize :: s -> Maybe ByteString,
Serial s -> ByteString -> Maybe s
deserialize :: ByteString -> Maybe s
}
gzip :: ByteString -> ByteString
gzip :: ByteString -> ByteString
gzip = [ByteString] -> ByteString
P.concat ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
toChunks (ByteString -> [ByteString])
-> (ByteString -> ByteString) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
compress (ByteString -> ByteString)
-> (ByteString -> ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
fromChunks ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[])
gunzip :: ByteString -> ByteString
gunzip :: ByteString -> ByteString
gunzip = [ByteString] -> ByteString
P.concat ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
toChunks (ByteString -> [ByteString])
-> (ByteString -> ByteString) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
decompress (ByteString -> ByteString)
-> (ByteString -> ByteString) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
fromChunks ([ByteString] -> ByteString)
-> (ByteString -> [ByteString]) -> ByteString -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
:[])
readOnly :: (ByteString -> b) -> Serial b
readOnly :: (ByteString -> b) -> Serial b
readOnly ByteString -> b
f = (b -> Maybe ByteString) -> (ByteString -> Maybe b) -> Serial b
forall s.
(s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
Serial (Maybe ByteString -> b -> Maybe ByteString
forall a b. a -> b -> a
const Maybe ByteString
forall a. Maybe a
Nothing) (b -> Maybe b
forall a. a -> Maybe a
Just (b -> Maybe b) -> (ByteString -> b) -> ByteString -> Maybe b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> b
f)
stdSerial :: (Show s, Read s) => Serial s
stdSerial :: Serial s
stdSerial = (s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
forall s.
(s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
Serial (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just(ByteString -> Maybe ByteString)
-> (s -> ByteString) -> s -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
P.pack(String -> ByteString) -> (s -> String) -> s -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
.s -> String
forall a. Show a => a -> String
show) (String -> Maybe s
forall (m :: * -> *) a. (MonadFail m, Read a) => String -> m a
readM(String -> Maybe s)
-> (ByteString -> String) -> ByteString -> Maybe s
forall b c a. (b -> c) -> (a -> b) -> a -> c
.ByteString -> String
P.unpack)
mapSerial :: (Ord k, Show k, Show v, Read k, Read v) => Serial (Map k v)
mapSerial :: Serial (Map k v)
mapSerial = Serial :: forall s.
(s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
Serial {
serialize :: Map k v -> Maybe ByteString
serialize = ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Map k v -> ByteString) -> Map k v -> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> ByteString
P.pack (String -> ByteString)
-> (Map k v -> String) -> Map k v -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [String] -> String
unlines ([String] -> String) -> (Map k v -> [String]) -> Map k v -> String
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((k, v) -> String) -> [(k, v)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (k, v) -> String
forall a. Show a => a -> String
show ([(k, v)] -> [String])
-> (Map k v -> [(k, v)]) -> Map k v -> [String]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map k v -> [(k, v)]
forall k a. Map k a -> [(k, a)]
M.toList,
deserialize :: ByteString -> Maybe (Map k v)
deserialize = Map k v -> Maybe (Map k v)
forall a. a -> Maybe a
Just (Map k v -> Maybe (Map k v))
-> (ByteString -> Map k v) -> ByteString -> Maybe (Map k v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(k, v)] -> Map k v
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(k, v)] -> Map k v)
-> (ByteString -> [(k, v)]) -> ByteString -> Map k v
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (ByteString -> Maybe (k, v)) -> [ByteString] -> [(k, v)]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe (String -> Maybe (k, v)
forall (m :: * -> *) a. (MonadFail m, Read a) => String -> m a
readM (String -> Maybe (k, v))
-> (ByteString -> String) -> ByteString -> Maybe (k, v)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
P.unpack) ([ByteString] -> [(k, v)])
-> (ByteString -> [ByteString]) -> ByteString -> [(k, v)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
P.lines
}
readM :: (MonadFail m, Read a) => String -> m a
readM :: String -> m a
readM String
s = case [a
x | (a
x,String
t) <- {-# SCC "Serial.readM.reads" #-} ReadS a
forall a. Read a => ReadS a
reads String
s
, (String
"",String
"") <- ReadS String
lex String
t] of
[a
x] -> a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return a
x
[] -> String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Serial.readM: no parse"
[a]
_ -> String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"Serial.readM: ambiguous parse"
class Packable t where
readPacked :: ByteString -> t
showPacked :: t -> ByteString
instance Packable (Map ByteString [ByteString]) where
readPacked :: ByteString -> Map ByteString [ByteString]
readPacked ByteString
ps = [(ByteString, [ByteString])] -> Map ByteString [ByteString]
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([ByteString] -> [(ByteString, [ByteString])]
readKV ( ByteString -> [ByteString]
P.lines (ByteString -> [ByteString])
-> (ByteString -> ByteString) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
gunzip (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ ByteString
ps))
where
readKV :: [ByteString] -> [(ByteString,[ByteString])]
readKV :: [ByteString] -> [(ByteString, [ByteString])]
readKV [] = []
readKV (ByteString
k:[ByteString]
rest) = let ([ByteString]
vs, [ByteString]
rest') = (ByteString -> Bool)
-> [ByteString] -> ([ByteString], [ByteString])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break (ByteString -> ByteString -> Bool
forall a. Eq a => a -> a -> Bool
== ByteString
P.empty) [ByteString]
rest
in (ByteString
k,[ByteString]
vs) (ByteString, [ByteString])
-> [(ByteString, [ByteString])] -> [(ByteString, [ByteString])]
forall a. a -> [a] -> [a]
: [ByteString] -> [(ByteString, [ByteString])]
readKV (Int -> [ByteString] -> [ByteString]
forall a. Int -> [a] -> [a]
drop Int
1 [ByteString]
rest')
showPacked :: Map ByteString [ByteString] -> ByteString
showPacked Map ByteString [ByteString]
m = ByteString -> ByteString
gzip
(ByteString -> ByteString)
-> ([(ByteString, [ByteString])] -> ByteString)
-> [(ByteString, [ByteString])]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
P.unlines
([ByteString] -> ByteString)
-> ([(ByteString, [ByteString])] -> [ByteString])
-> [(ByteString, [ByteString])]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ByteString, [ByteString]) -> [ByteString])
-> [(ByteString, [ByteString])] -> [ByteString]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(ByteString
k,[ByteString]
vs) -> ByteString
k ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: [ByteString]
vs [ByteString] -> [ByteString] -> [ByteString]
forall a. [a] -> [a] -> [a]
++ [ByteString
P.empty]) ([(ByteString, [ByteString])] -> ByteString)
-> [(ByteString, [ByteString])] -> ByteString
forall a b. (a -> b) -> a -> b
$ Map ByteString [ByteString] -> [(ByteString, [ByteString])]
forall k a. Map k a -> [(k, a)]
M.toList Map ByteString [ByteString]
m
instance Packable (Map ByteString ByteString) where
readPacked :: ByteString -> Map ByteString ByteString
readPacked ByteString
ps = [(ByteString, ByteString)] -> Map ByteString ByteString
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([ByteString] -> [(ByteString, ByteString)]
readKV (ByteString -> [ByteString]
P.lines (ByteString -> [ByteString])
-> (ByteString -> ByteString) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
gunzip (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ ByteString
ps))
where
readKV :: [ByteString] -> [(ByteString,ByteString)]
readKV :: [ByteString] -> [(ByteString, ByteString)]
readKV [] = []
readKV (ByteString
k:ByteString
v:[ByteString]
rest) = (ByteString
k,ByteString
v) (ByteString, ByteString)
-> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
forall a. a -> [a] -> [a]
: [ByteString] -> [(ByteString, ByteString)]
readKV [ByteString]
rest
readKV [ByteString]
_ = String -> [(ByteString, ByteString)]
forall a. HasCallStack => String -> a
error String
"Serial.readPacked: parse failed"
showPacked :: Map ByteString ByteString -> ByteString
showPacked Map ByteString ByteString
m = ByteString -> ByteString
gzip(ByteString -> ByteString)
-> ([(ByteString, ByteString)] -> ByteString)
-> [(ByteString, ByteString)]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
P.unlines ([ByteString] -> ByteString)
-> ([(ByteString, ByteString)] -> [ByteString])
-> [(ByteString, ByteString)]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ByteString, ByteString) -> [ByteString])
-> [(ByteString, ByteString)] -> [ByteString]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(ByteString
k,ByteString
v) -> [ByteString
k,ByteString
v]) ([(ByteString, ByteString)] -> ByteString)
-> [(ByteString, ByteString)] -> ByteString
forall a b. (a -> b) -> a -> b
$ Map ByteString ByteString -> [(ByteString, ByteString)]
forall k a. Map k a -> [(k, a)]
M.toList Map ByteString ByteString
m
instance Packable ([(ByteString,ByteString)]) where
readPacked :: ByteString -> [(ByteString, ByteString)]
readPacked ByteString
ps = [ByteString] -> [(ByteString, ByteString)]
readKV (ByteString -> [ByteString]
P.lines (ByteString -> [ByteString])
-> (ByteString -> ByteString) -> ByteString -> [ByteString]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ByteString
gunzip (ByteString -> [ByteString]) -> ByteString -> [ByteString]
forall a b. (a -> b) -> a -> b
$ ByteString
ps)
where
readKV :: [ByteString] -> [(ByteString,ByteString)]
readKV :: [ByteString] -> [(ByteString, ByteString)]
readKV [] = []
readKV (ByteString
k:ByteString
v:[ByteString]
rest) = (ByteString
k,ByteString
v) (ByteString, ByteString)
-> [(ByteString, ByteString)] -> [(ByteString, ByteString)]
forall a. a -> [a] -> [a]
: [ByteString] -> [(ByteString, ByteString)]
readKV [ByteString]
rest
readKV [ByteString]
_ = String -> [(ByteString, ByteString)]
forall a. HasCallStack => String -> a
error String
"Serial.readPacked: parse failed"
showPacked :: [(ByteString, ByteString)] -> ByteString
showPacked = ByteString -> ByteString
gzip (ByteString -> ByteString)
-> ([(ByteString, ByteString)] -> ByteString)
-> [(ByteString, ByteString)]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> ByteString
P.unlines ([ByteString] -> ByteString)
-> ([(ByteString, ByteString)] -> [ByteString])
-> [(ByteString, ByteString)]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ByteString, ByteString) -> [ByteString])
-> [(ByteString, ByteString)] -> [ByteString]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(ByteString
k,ByteString
v) -> [ByteString
k,ByteString
v])
instance Packable (M.Map P.ByteString (Bool, [(P.ByteString, Int)])) where
readPacked :: ByteString -> Map ByteString (Bool, [(ByteString, Int)])
readPacked = [(ByteString, (Bool, [(ByteString, Int)]))]
-> Map ByteString (Bool, [(ByteString, Int)])
forall k a. Ord k => [(k, a)] -> Map k a
M.fromList ([(ByteString, (Bool, [(ByteString, Int)]))]
-> Map ByteString (Bool, [(ByteString, Int)]))
-> (ByteString -> [(ByteString, (Bool, [(ByteString, Int)]))])
-> ByteString
-> Map ByteString (Bool, [(ByteString, Int)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [ByteString] -> [(ByteString, (Bool, [(ByteString, Int)]))]
readKV ([ByteString] -> [(ByteString, (Bool, [(ByteString, Int)]))])
-> (ByteString -> [ByteString])
-> ByteString
-> [(ByteString, (Bool, [(ByteString, Int)]))]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [ByteString]
P.lines
where
readKV :: [P.ByteString] -> [(P.ByteString,(Bool, [(P.ByteString, Int)]))]
readKV :: [ByteString] -> [(ByteString, (Bool, [(ByteString, Int)]))]
readKV [] = []
readKV (ByteString
k:ByteString
v:[ByteString]
rest) = (ByteString
k, (String -> (Bool, [(ByteString, Int)])
forall a. Read a => String -> a
read (String -> (Bool, [(ByteString, Int)]))
-> (ByteString -> String)
-> ByteString
-> (Bool, [(ByteString, Int)])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> String
P.unpack) ByteString
v) (ByteString, (Bool, [(ByteString, Int)]))
-> [(ByteString, (Bool, [(ByteString, Int)]))]
-> [(ByteString, (Bool, [(ByteString, Int)]))]
forall a. a -> [a] -> [a]
: [ByteString] -> [(ByteString, (Bool, [(ByteString, Int)]))]
readKV [ByteString]
rest
readKV [ByteString]
_ = String -> [(ByteString, (Bool, [(ByteString, Int)]))]
forall a. HasCallStack => String -> a
error String
"Vote.readPacked: parse failed"
showPacked :: Map ByteString (Bool, [(ByteString, Int)]) -> ByteString
showPacked Map ByteString (Bool, [(ByteString, Int)])
m = [ByteString] -> ByteString
P.unlines ([ByteString] -> ByteString)
-> ([(ByteString, (Bool, [(ByteString, Int)]))] -> [ByteString])
-> [(ByteString, (Bool, [(ByteString, Int)]))]
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ((ByteString, (Bool, [(ByteString, Int)])) -> [ByteString])
-> [(ByteString, (Bool, [(ByteString, Int)]))] -> [ByteString]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap (\(ByteString
k,(Bool, [(ByteString, Int)])
v) -> [ByteString
k,String -> ByteString
P.pack (String -> ByteString)
-> ((Bool, [(ByteString, Int)]) -> String)
-> (Bool, [(ByteString, Int)])
-> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Bool, [(ByteString, Int)]) -> String
forall a. Show a => a -> String
show ((Bool, [(ByteString, Int)]) -> ByteString)
-> (Bool, [(ByteString, Int)]) -> ByteString
forall a b. (a -> b) -> a -> b
$ (Bool, [(ByteString, Int)])
v]) ([(ByteString, (Bool, [(ByteString, Int)]))] -> ByteString)
-> [(ByteString, (Bool, [(ByteString, Int)]))] -> ByteString
forall a b. (a -> b) -> a -> b
$ Map ByteString (Bool, [(ByteString, Int)])
-> [(ByteString, (Bool, [(ByteString, Int)]))]
forall k a. Map k a -> [(k, a)]
M.toList Map ByteString (Bool, [(ByteString, Int)])
m
mapPackedSerial :: Serial (Map ByteString ByteString)
mapPackedSerial :: Serial (Map ByteString ByteString)
mapPackedSerial = (Map ByteString ByteString -> Maybe ByteString)
-> (ByteString -> Maybe (Map ByteString ByteString))
-> Serial (Map ByteString ByteString)
forall s.
(s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
Serial (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Map ByteString ByteString -> ByteString)
-> Map ByteString ByteString
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map ByteString ByteString -> ByteString
forall t. Packable t => t -> ByteString
showPacked) (Map ByteString ByteString -> Maybe (Map ByteString ByteString)
forall a. a -> Maybe a
Just (Map ByteString ByteString -> Maybe (Map ByteString ByteString))
-> (ByteString -> Map ByteString ByteString)
-> ByteString
-> Maybe (Map ByteString ByteString)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Map ByteString ByteString
forall t. Packable t => ByteString -> t
readPacked)
mapListPackedSerial :: Serial (Map ByteString [ByteString])
mapListPackedSerial :: Serial (Map ByteString [ByteString])
mapListPackedSerial = (Map ByteString [ByteString] -> Maybe ByteString)
-> (ByteString -> Maybe (Map ByteString [ByteString]))
-> Serial (Map ByteString [ByteString])
forall s.
(s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
Serial (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> (Map ByteString [ByteString] -> ByteString)
-> Map ByteString [ByteString]
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Map ByteString [ByteString] -> ByteString
forall t. Packable t => t -> ByteString
showPacked) (Map ByteString [ByteString] -> Maybe (Map ByteString [ByteString])
forall a. a -> Maybe a
Just (Map ByteString [ByteString]
-> Maybe (Map ByteString [ByteString]))
-> (ByteString -> Map ByteString [ByteString])
-> ByteString
-> Maybe (Map ByteString [ByteString])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> Map ByteString [ByteString]
forall t. Packable t => ByteString -> t
readPacked)
assocListPackedSerial :: Serial ([(ByteString,ByteString)])
assocListPackedSerial :: Serial [(ByteString, ByteString)]
assocListPackedSerial = ([(ByteString, ByteString)] -> Maybe ByteString)
-> (ByteString -> Maybe [(ByteString, ByteString)])
-> Serial [(ByteString, ByteString)]
forall s.
(s -> Maybe ByteString) -> (ByteString -> Maybe s) -> Serial s
Serial (ByteString -> Maybe ByteString
forall a. a -> Maybe a
Just (ByteString -> Maybe ByteString)
-> ([(ByteString, ByteString)] -> ByteString)
-> [(ByteString, ByteString)]
-> Maybe ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [(ByteString, ByteString)] -> ByteString
forall t. Packable t => t -> ByteString
showPacked) ([(ByteString, ByteString)] -> Maybe [(ByteString, ByteString)]
forall a. a -> Maybe a
Just ([(ByteString, ByteString)] -> Maybe [(ByteString, ByteString)])
-> (ByteString -> [(ByteString, ByteString)])
-> ByteString
-> Maybe [(ByteString, ByteString)]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> [(ByteString, ByteString)]
forall t. Packable t => ByteString -> t
readPacked)