{-# LANGUAGE FlexibleInstances #-}

{- Copyright (c) 2004-5 Thomas Jaeger, Don Stewart

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
02111-1307, USA. -}

-- | Serialisation
module Lambdabot.Util.Serial
    ( Serial(..)
    
    , stdSerial
    , mapSerial
    , mapPackedSerial
    , assocListPackedSerial
    , mapListPackedSerial
    , readM
    , Packable(..) {- instances of 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

------------------------------------------------------------------------

-- A flexible (moreso than a typeclass) way to define introduction and
-- elimination for persistent state on a per-module basis.
--
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]
:[])

--
-- read-only serialisation
--
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)

-- | Default `instance' for a Serial
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)

-- | Serializes a 'Map' type if both the key and the value are instances
-- of Read and Show. The serialization is done by converting the map to
-- and from lists. Results are saved line-wise, for better editing and
-- revision control.
--
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' behaves like read, but catches failure in a monad.
-- this allocates a 20-30 M on startup...
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    -- bad!
               , (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

-- | An instance for Map Packed [Packed]
-- uses gzip compression
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

-- assumes single line second strings
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])

-- The following instance is used by the `poll` plugin.
-- The `read` and `show` are there for backward compatibility.
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

-- And for packed string maps
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)

-- And for list of packed string maps
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)

-- And for association list
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)

------------------------------------------------------------------------