{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleContexts #-} -- | This module contains various extra Binary instances, for example ones -- which are particular GHC or uni-specific. module Util.BinaryExtras( hReadLtd, -- :: HasBinary a IO => Int -> Handle -> IO (WithError a) initialClockTime, -- :: ClockTime -- static clock time, used in other modules. ) where import System.IO import Data.IORef import System.Time import Util.Binary import Util.BinaryUtils import Util.Computation import Util.ExtendedPrelude import Util.IOExtras import Util.BinaryInstances() -- | Read something, but throw an exception if there is an attempt to -- read too many characters. hReadLtd :: HasBinary a IO => Int -- ^ the maximum number of characters -> Handle -> IO (WithError a) hReadLtd limit handle = addFallOutWE (\ break -> do lenIORef <- newIORef 0 let ensure :: Int -> IO () ensure i = do len1 <- simpleModifyIORef lenIORef (\ len0 -> let len1 = len0 + i in (len1,len1) ) if len1 > limit then break "BinaryExtras.hReadLtd: limit exceeded" else done (ReadBinary {readByte = readByte1,readBytes = readBytes1}) = toReadBinaryHandle handle readByte2 = do ensure 1 readByte1 readBytes2 len = do ensure len readBytes1 len rb2 = ReadBinary {readByte = readByte2,readBytes = readBytes2} readBin rb2 ) -- ---------------------------------------------------------------------- -- Instance for ClockTime -- ---------------------------------------------------------------------- instance Monad m => HasBinary ClockTime m where writeBin = mapWrite (\ (TOD i j) -> (i,j)) readBin = mapRead (\ (i,j) -> TOD i j) -- | Time this code was written. We bung this definition in here -- because this module needs GHC-specific access to ClockTime anyway. initialClockTime :: ClockTime initialClockTime = TOD 1052391874 190946000000