{-# 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 #-}