{-# OPTIONS_GHC -fno-warn-orphans #-}
module Data.Strict.Containers.Serialise
(
) where
import Codec.CBOR.Decoding
import Codec.CBOR.Encoding
import Codec.Serialise.Class
import Data.Hashable (Hashable)
import Data.Semigroup (Semigroup (..)) -- helps with compatibility
import qualified Data.Foldable as Foldable
import qualified Data.Strict.HashMap as HashMap
import qualified Data.Strict.IntMap as IntMap
import qualified Data.Strict.Map as Map
import qualified Data.Strict.Sequence as Sequence
import qualified Data.Strict.Vector as Vector
-- code copied from serialise
decodeContainerSkelWithReplicate
:: (Serialise a)
=> Decoder s Int
-- ^ How to get the size of the container
-> (Int -> Decoder s a -> Decoder s container)
-- ^ replicateM for the container
-> ([container] -> container)
-- ^ concat for the container
-> Decoder s container
decodeContainerSkelWithReplicate decodeLen replicateFun fromList = do
-- Look at how much data we have at the moment and use it as the limit for
-- the size of a single call to replicateFun. We don't want to use
-- replicateFun directly on the result of decodeLen since this might lead to
-- DOS attack (attacker providing a huge value for length). So if it's above
-- our limit, we'll do manual chunking and then combine the containers into
-- one.
size <- decodeLen
limit <- peekAvailable
if size <= limit
then replicateFun size decode
else do
-- Take the max of limit and a fixed chunk size (note: limit can be
-- 0). This basically means that the attacker can make us allocate a
-- container of size 128 even though there's no actual input.
let chunkSize = max limit 128
(d, m) = size `divMod` chunkSize
buildOne s = replicateFun s decode
containers <- sequence $ buildOne m : replicate d (buildOne chunkSize)
return $! fromList containers
{-# INLINE decodeContainerSkelWithReplicate #-}
instance (Ord k, Serialise k, Serialise v) => Serialise (Map.Map k v) where
encode = encodeMapSkel Map.size Map.foldrWithKey
decode = decodeMapSkel Map.fromList
instance (Serialise k, Hashable k, Eq k, Serialise v) =>
Serialise (HashMap.HashMap k v) where
encode = encodeMapSkel HashMap.size HashMap.foldrWithKey
decode = decodeMapSkel HashMap.fromList
instance (Serialise a) => Serialise (IntMap.IntMap a) where
encode = encodeMapSkel IntMap.size IntMap.foldrWithKey
decode = decodeMapSkel IntMap.fromList
instance (Serialise a) => Serialise (Sequence.Seq a) where
encode = encodeContainerSkel
encodeListLen
Sequence.length
Foldable.foldr
(\a b -> encode a <> b)
decode = decodeContainerSkelWithReplicate
decodeListLen
Sequence.replicateM
mconcat
instance (Serialise a) => Serialise (Vector.Vector a) where
encode = encodeVector
{-# INLINE encode #-}
decode = decodeVector
{-# INLINE decode #-}