summaryrefslogtreecommitdiff
path: root/compiler/utils/Binary.hs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/utils/Binary.hs')
-rw-r--r--compiler/utils/Binary.hs1654
1 files changed, 560 insertions, 1094 deletions
diff --git a/compiler/utils/Binary.hs b/compiler/utils/Binary.hs
index 94a09288b5..51d7db1fdf 100644
--- a/compiler/utils/Binary.hs
+++ b/compiler/utils/Binary.hs
@@ -1,660 +1,361 @@
-{-# LANGUAGE CPP #-}
-{-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE PolyKinds #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-{-# LANGUAGE GADTs #-}
-{-# LANGUAGE MultiWayIf #-}
-{-# LANGUAGE BangPatterns #-}
-
{-# OPTIONS_GHC -O2 -funbox-strict-fields #-}
--- We always optimise this, otherwise performance of a non-optimised
--- compiler is severely affected
-
---
--- (c) The University of Glasgow 2002-2006
---
--- Binary I/O library, with special tweaks for GHC
---
--- Based on the nhc98 Binary library, which is copyright
--- (c) Malcolm Wallace and Colin Runciman, University of York, 1998.
--- Under the terms of the license for that software, we must tell you
--- where you can obtain the original version of the Binary library, namely
--- http://www.cs.york.ac.uk/fp/nhc98/
-
-module Binary
- ( {-type-} Bin,
- {-class-} Binary(..),
- {-type-} BinHandle,
- SymbolTable, Dictionary,
-
- openBinMem,
--- closeBin,
-
- seekBin,
- seekBy,
- tellBin,
- castBin,
- isEOFBin,
- withBinBuffer,
-
- writeBinMem,
- readBinMem,
-
- putAt, getAt,
-
- -- * For writing instances
- putByte,
- getByte,
-
- -- * Variable length encodings
- putULEB128,
- getULEB128,
- putSLEB128,
- getSLEB128,
-
- -- * Lazy Binary I/O
- lazyGet,
- lazyPut,
-
- -- * User data
- UserData(..), getUserData, setUserData,
- newReadState, newWriteState,
- putDictionary, getDictionary, putFS,
- ) where
-
-#include "HsVersions.h"
+{-# LANGUAGE DeriveGeneric, DefaultSignatures, KindSignatures, FlexibleContexts, TypeOperators, StandaloneDeriving, DeriveAnyClass, BangPatterns, TypeApplications, AllowAmbiguousTypes, DataKinds, TypeFamilies, MagicHash, ScopedTypeVariables, UndecidableInstances, FlexibleInstances, CPP, MultiWayIf, PolyKinds #-}
-import GhcPrelude
+module Binary (
-import {-# SOURCE #-} Name (Name)
-import FastString
-import PlainPanic
-import UniqFM
-import FastMutInt
-import Fingerprint
-import BasicTypes
-import SrcLoc
+ Binary(..),
+
+ putAt, getAt,
+ putTo, getFrom,
+ lazyPut, lazyGet,
+
+ encode, decode,
+
+ module Binary.Internal,
+
+) where
+
+import Binary.Internal
+
+import Data.Char
import Foreign
+import GHC.Generics
+
+import BasicTypes
import Data.Array
-import Data.ByteString (ByteString)
-import qualified Data.ByteString.Internal as BS
-import qualified Data.ByteString.Unsafe as BS
-import Data.IORef
-import Data.Char ( ord, chr )
+import Data.Kind (Type)
import Data.Time
-import Data.List (unfoldr)
+import SrcLoc
+import Fingerprint
+import GHC.Serialized
import Type.Reflection
import Type.Reflection.Unsafe
-import Data.Kind (Type)
-import GHC.Exts (TYPE, RuntimeRep(..), VecCount(..), VecElem(..))
-import Control.Monad ( when, (<$!>), unless )
-import System.IO as IO
-import System.IO.Unsafe ( unsafeInterleaveIO )
-import System.IO.Error ( mkIOError, eofErrorType )
-import GHC.Real ( Ratio(..) )
-import GHC.Serialized
+import GHC.Real (Ratio(..))
-type BinArray = ForeignPtr Word8
+import Control.Monad
+import Data.List
----------------------------------------------------------------
--- BinHandle
----------------------------------------------------------------
+import GhcPrelude
+import FastString
+import PlainPanic
-data BinHandle
- = BinMem { -- binary data stored in an unboxed array
- bh_usr :: UserData, -- sigh, need parameterized modules :-)
- _off_r :: !FastMutInt, -- the current offset
- _sz_r :: !FastMutInt, -- size of the array (cached)
- _arr_r :: !(IORef BinArray) -- the array (bounds: (0,size-1))
- }
- -- XXX: should really store a "high water mark" for dumping out
- -- the binary data to a file.
+import qualified Data.ByteString as Strict
+import qualified Data.ByteString.Lazy as Lazy
-getUserData :: BinHandle -> UserData
-getUserData bh = bh_usr bh
+import GHC.TypeLits
+import GHC.Exts
-setUserData :: BinHandle -> UserData -> BinHandle
-setUserData bh us = bh { bh_usr = us }
+-- -----------------------------------------------------------------------------
+-- Class
+-- -----------------------------------------------------------------------------
--- | Get access to the underlying buffer.
---
--- It is quite important that no references to the 'ByteString' leak out of the
--- continuation lest terrible things happen.
-withBinBuffer :: BinHandle -> (ByteString -> IO a) -> IO a
-withBinBuffer (BinMem _ ix_r _ arr_r) action = do
- arr <- readIORef arr_r
- ix <- readFastMutInt ix_r
- withForeignPtr arr $ \ptr ->
- BS.unsafePackCStringLen (castPtr ptr, ix) >>= action
+class Binary a where
+ put :: a -> Put ()
+ get :: Get a
+ default put :: (Generic a, GBinary (Rep a)) => a -> Put ()
+ put = gput . from
----------------------------------------------------------------
--- Bin
----------------------------------------------------------------
+ default get :: (Generic a, GBinary (Rep a)) => Get a
+ get = to <$> gget
-newtype Bin a = BinPtr Int
- deriving (Eq, Ord, Show, Bounded)
+-- -----------------------------------------------------------------------------
+-- Convenience functions
+-- -----------------------------------------------------------------------------
-castBin :: Bin a -> Bin b
-castBin (BinPtr i) = BinPtr i
+encode :: Binary a => a -> BinData
+encode = runPut . put
+
+decode :: Binary a => BinData -> a
+decode bd = runGet bd get
+
+-- Put the argument at the specified pointer, leaving the current index
+-- at the location after that.
+putAt :: Binary a => Bin a -> a -> Put ()
+putAt ptr x = seekP ptr >> put x
+
+-- Get data from the specified pointer, leaving the current index at the
+-- location after that.
+getAt :: Binary a => Bin a -> Get a
+getAt ptr = seekG ptr >> get
+
+-- Put the argument at the specified pointer, and return to the current
+-- location afterwards.
+putTo :: Binary a => Bin a -> a -> Put ()
+putTo ptr x = do
+ here <- tellP
+ seekP ptr
+ put x
+ seekP here
+
+-- Get data from the specified pointer, and return to the current location
+-- afterwards.
+getFrom :: Binary a => Bin a -> Get a
+getFrom ptr = do
+ here <- tellG
+ seekG ptr
+ x <- get
+ seekG here
+ return x
----------------------------------------------------------------
--- class Binary
----------------------------------------------------------------
+-- -----------------------------------------------------------------------------
+-- Lazy reading and writing
+-- -----------------------------------------------------------------------------
--- | Do not rely on instance sizes for general types,
--- we use variable length encoding for many of them.
-class Binary a where
- put_ :: BinHandle -> a -> IO ()
- put :: BinHandle -> a -> IO (Bin a)
- get :: BinHandle -> IO a
-
- -- define one of put_, put. Use of put_ is recommended because it
- -- is more likely that tail-calls can kick in, and we rarely need the
- -- position return value.
- put_ bh a = do _ <- put bh a; return ()
- put bh a = do p <- tellBin bh; put_ bh a; return p
-
-putAt :: Binary a => BinHandle -> Bin a -> a -> IO ()
-putAt bh p x = do seekBin bh p; put_ bh x; return ()
-
-getAt :: Binary a => BinHandle -> Bin a -> IO a
-getAt bh p = do seekBin bh p; get bh
-
-openBinMem :: Int -> IO BinHandle
-openBinMem size
- | size <= 0 = error "Data.Binary.openBinMem: size must be >= 0"
- | otherwise = do
- arr <- mallocForeignPtrBytes size
- arr_r <- newIORef arr
- ix_r <- newFastMutInt
- writeFastMutInt ix_r 0
- sz_r <- newFastMutInt
- writeFastMutInt sz_r size
- return (BinMem noUserData ix_r sz_r arr_r)
-
-tellBin :: BinHandle -> IO (Bin a)
-tellBin (BinMem _ r _ _) = do ix <- readFastMutInt r; return (BinPtr ix)
-
-seekBin :: BinHandle -> Bin a -> IO ()
-seekBin h@(BinMem _ ix_r sz_r _) (BinPtr !p) = do
- sz <- readFastMutInt sz_r
- if (p >= sz)
- then do expandBin h p; writeFastMutInt ix_r p
- else writeFastMutInt ix_r p
-
-seekBy :: BinHandle -> Int -> IO ()
-seekBy h@(BinMem _ ix_r sz_r _) !off = do
- sz <- readFastMutInt sz_r
- ix <- readFastMutInt ix_r
- let ix' = ix + off
- if (ix' >= sz)
- then do expandBin h ix'; writeFastMutInt ix_r ix'
- else writeFastMutInt ix_r ix'
-
-isEOFBin :: BinHandle -> IO Bool
-isEOFBin (BinMem _ ix_r sz_r _) = do
- ix <- readFastMutInt ix_r
- sz <- readFastMutInt sz_r
- return (ix >= sz)
-
-writeBinMem :: BinHandle -> FilePath -> IO ()
-writeBinMem (BinMem _ ix_r _ arr_r) fn = do
- h <- openBinaryFile fn WriteMode
- arr <- readIORef arr_r
- ix <- readFastMutInt ix_r
- withForeignPtr arr $ \p -> hPutBuf h p ix
- hClose h
-
-readBinMem :: FilePath -> IO BinHandle
--- Return a BinHandle with a totally undefined State
-readBinMem filename = do
- h <- openBinaryFile filename ReadMode
- filesize' <- hFileSize h
- let filesize = fromIntegral filesize'
- arr <- mallocForeignPtrBytes filesize
- count <- withForeignPtr arr $ \p -> hGetBuf h p filesize
- when (count /= filesize) $
- error ("Binary.readBinMem: only read " ++ show count ++ " bytes")
- hClose h
- arr_r <- newIORef arr
- ix_r <- newFastMutInt
- writeFastMutInt ix_r 0
- sz_r <- newFastMutInt
- writeFastMutInt sz_r filesize
- return (BinMem noUserData ix_r sz_r arr_r)
-
--- expand the size of the array to include a specified offset
-expandBin :: BinHandle -> Int -> IO ()
-expandBin (BinMem _ _ sz_r arr_r) !off = do
- !sz <- readFastMutInt sz_r
- let !sz' = getSize sz
- arr <- readIORef arr_r
- arr' <- mallocForeignPtrBytes sz'
- withForeignPtr arr $ \old ->
- withForeignPtr arr' $ \new ->
- copyBytes new old sz
- writeFastMutInt sz_r sz'
- writeIORef arr_r arr'
- where
- getSize :: Int -> Int
- getSize !sz
- | sz > off
- = sz
- | otherwise
- = getSize (sz * 2)
+lazyPut :: Binary a => a -> Put ()
+lazyPut a = do
+ p_a <- tellP
+ put p_a
+ put a
+ q <- tellP
+ putAt p_a q
+ seekP q
+
+lazyGet :: Binary a => Get a
+lazyGet = do
+ p <- get
+ p_a <- tellG
+ a <- getSlice p . interleaveG $ getAt p_a
+ seekG p
+ return a
-- -----------------------------------------------------------------------------
--- Low-level reading/writing of bytes
-
--- | Takes a size and action writing up to @size@ bytes.
--- After the action has run advance the index to the buffer
--- by size bytes.
-putPrim :: BinHandle -> Int -> (Ptr Word8 -> IO ()) -> IO ()
-putPrim h@(BinMem _ ix_r sz_r arr_r) size f = do
- ix <- readFastMutInt ix_r
- sz <- readFastMutInt sz_r
- when (ix + size > sz) $
- expandBin h (ix + size)
- arr <- readIORef arr_r
- withForeignPtr arr $ \op -> f (op `plusPtr` ix)
- writeFastMutInt ix_r (ix + size)
-
--- -- | Similar to putPrim but advances the index by the actual number of
--- -- bytes written.
--- putPrimMax :: BinHandle -> Int -> (Ptr Word8 -> IO Int) -> IO ()
--- putPrimMax h@(BinMem _ ix_r sz_r arr_r) size f = do
--- ix <- readFastMutInt ix_r
--- sz <- readFastMutInt sz_r
--- when (ix + size > sz) $
--- expandBin h (ix + size)
--- arr <- readIORef arr_r
--- written <- withForeignPtr arr $ \op -> f (op `plusPtr` ix)
--- writeFastMutInt ix_r (ix + written)
-
-getPrim :: BinHandle -> Int -> (Ptr Word8 -> IO a) -> IO a
-getPrim (BinMem _ ix_r sz_r arr_r) size f = do
- ix <- readFastMutInt ix_r
- sz <- readFastMutInt sz_r
- when (ix + size > sz) $
- ioError (mkIOError eofErrorType "Data.Binary.getPrim" Nothing Nothing)
- arr <- readIORef arr_r
- w <- withForeignPtr arr $ \op -> f (op `plusPtr` ix)
- writeFastMutInt ix_r (ix + size)
- return w
-
-putWord8 :: BinHandle -> Word8 -> IO ()
-putWord8 h !w = putPrim h 1 (\op -> poke op w)
-
-getWord8 :: BinHandle -> IO Word8
-getWord8 h = getPrim h 1 peek
-
--- putWord16 :: BinHandle -> Word16 -> IO ()
--- putWord16 h w = putPrim h 2 (\op -> do
--- pokeElemOff op 0 (fromIntegral (w `shiftR` 8))
--- pokeElemOff op 1 (fromIntegral (w .&. 0xFF))
--- )
-
--- getWord16 :: BinHandle -> IO Word16
--- getWord16 h = getPrim h 2 (\op -> do
--- w0 <- fromIntegral <$> peekElemOff op 0
--- w1 <- fromIntegral <$> peekElemOff op 1
--- return $! w0 `shiftL` 8 .|. w1
--- )
-
-putWord32 :: BinHandle -> Word32 -> IO ()
-putWord32 h w = putPrim h 4 (\op -> do
- pokeElemOff op 0 (fromIntegral (w `shiftR` 24))
- pokeElemOff op 1 (fromIntegral ((w `shiftR` 16) .&. 0xFF))
- pokeElemOff op 2 (fromIntegral ((w `shiftR` 8) .&. 0xFF))
- pokeElemOff op 3 (fromIntegral (w .&. 0xFF))
- )
-
-getWord32 :: BinHandle -> IO Word32
-getWord32 h = getPrim h 4 (\op -> do
- w0 <- fromIntegral <$> peekElemOff op 0
- w1 <- fromIntegral <$> peekElemOff op 1
- w2 <- fromIntegral <$> peekElemOff op 2
- w3 <- fromIntegral <$> peekElemOff op 3
-
- return $! (w0 `shiftL` 24) .|.
- (w1 `shiftL` 16) .|.
- (w2 `shiftL` 8) .|.
- w3
- )
-
--- putWord64 :: BinHandle -> Word64 -> IO ()
--- putWord64 h w = putPrim h 8 (\op -> do
--- pokeElemOff op 0 (fromIntegral (w `shiftR` 56))
--- pokeElemOff op 1 (fromIntegral ((w `shiftR` 48) .&. 0xFF))
--- pokeElemOff op 2 (fromIntegral ((w `shiftR` 40) .&. 0xFF))
--- pokeElemOff op 3 (fromIntegral ((w `shiftR` 32) .&. 0xFF))
--- pokeElemOff op 4 (fromIntegral ((w `shiftR` 24) .&. 0xFF))
--- pokeElemOff op 5 (fromIntegral ((w `shiftR` 16) .&. 0xFF))
--- pokeElemOff op 6 (fromIntegral ((w `shiftR` 8) .&. 0xFF))
--- pokeElemOff op 7 (fromIntegral (w .&. 0xFF))
--- )
-
--- getWord64 :: BinHandle -> IO Word64
--- getWord64 h = getPrim h 8 (\op -> do
--- w0 <- fromIntegral <$> peekElemOff op 0
--- w1 <- fromIntegral <$> peekElemOff op 1
--- w2 <- fromIntegral <$> peekElemOff op 2
--- w3 <- fromIntegral <$> peekElemOff op 3
--- w4 <- fromIntegral <$> peekElemOff op 4
--- w5 <- fromIntegral <$> peekElemOff op 5
--- w6 <- fromIntegral <$> peekElemOff op 6
--- w7 <- fromIntegral <$> peekElemOff op 7
-
--- return $! (w0 `shiftL` 56) .|.
--- (w1 `shiftL` 48) .|.
--- (w2 `shiftL` 40) .|.
--- (w3 `shiftL` 32) .|.
--- (w4 `shiftL` 24) .|.
--- (w5 `shiftL` 16) .|.
--- (w6 `shiftL` 8) .|.
--- w7
--- )
-
-putByte :: BinHandle -> Word8 -> IO ()
-putByte bh !w = putWord8 bh w
-
-getByte :: BinHandle -> IO Word8
-getByte h = getWord8 h
-
+-- Generics
-- -----------------------------------------------------------------------------
--- Encode numbers in LEB128 encoding.
--- Requires one byte of space per 7 bits of data.
---
--- There are signed and unsigned variants.
--- Do NOT use the unsigned one for signed values, at worst it will
--- result in wrong results, at best it will lead to bad performance
--- when coercing negative values to an unsigned type.
---
--- We mark them as SPECIALIZE as it's extremely critical that they get specialized
--- to their specific types.
---
--- TODO: Each use of putByte performs a bounds check,
--- we should use putPrimMax here. However it's quite hard to return
--- the number of bytes written into putPrimMax without allocating an
--- Int for it, while the code below does not allocate at all.
--- So we eat the cost of the bounds check instead of increasing allocations
--- for now.
-
--- Unsigned numbers
-{-# SPECIALISE putULEB128 :: BinHandle -> Word -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Word64 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Word32 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Word16 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int64 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int32 -> IO () #-}
-{-# SPECIALISE putULEB128 :: BinHandle -> Int16 -> IO () #-}
-putULEB128 :: forall a. (Integral a, FiniteBits a) => BinHandle -> a -> IO ()
-putULEB128 bh w =
-#if defined(DEBUG)
- (if w < 0 then panic "putULEB128: Signed number" else id) $
-#endif
- go w
- where
- go :: a -> IO ()
- go w
- | w <= (127 :: a)
- = putByte bh (fromIntegral w :: Word8)
- | otherwise = do
- -- bit 7 (8th bit) indicates more to come.
- let !byte = setBit (fromIntegral w) 7 :: Word8
- putByte bh byte
- go (w `unsafeShiftR` 7)
-
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word64 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word32 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Word16 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int64 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int32 #-}
-{-# SPECIALISE getULEB128 :: BinHandle -> IO Int16 #-}
-getULEB128 :: forall a. (Integral a, FiniteBits a) => BinHandle -> IO a
-getULEB128 bh =
- go 0 0
- where
- go :: Int -> a -> IO a
- go shift w = do
- b <- getByte bh
- let !hasMore = testBit b 7
- let !val = w .|. ((clearBit (fromIntegral b) 7) `unsafeShiftL` shift) :: a
- if hasMore
- then do
- go (shift+7) val
- else
- return $! val
-
--- Signed numbers
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word64 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word32 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Word16 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int64 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int32 -> IO () #-}
-{-# SPECIALISE putSLEB128 :: BinHandle -> Int16 -> IO () #-}
-putSLEB128 :: forall a. (Integral a, Bits a) => BinHandle -> a -> IO ()
-putSLEB128 bh initial = go initial
- where
- go :: a -> IO ()
- go val = do
- let !byte = fromIntegral (clearBit val 7) :: Word8
- let !val' = val `unsafeShiftR` 7
- let !signBit = testBit byte 6
- let !done =
- -- Unsigned value, val' == 0 and last value can
- -- be discriminated from a negative number.
- ((val' == 0 && not signBit) ||
- -- Signed value,
- (val' == -1 && signBit))
-
- let !byte' = if done then byte else setBit byte 7
- putByte bh byte'
-
- unless done $ go val'
-
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word64 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word32 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Word16 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int64 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int32 #-}
-{-# SPECIALISE getSLEB128 :: BinHandle -> IO Int16 #-}
-getSLEB128 :: forall a. (Show a, Integral a, FiniteBits a) => BinHandle -> IO a
-getSLEB128 bh = do
- (val,shift,signed) <- go 0 0
- if signed && (shift < finiteBitSize val )
- then return $! ((complement 0 `unsafeShiftL` shift) .|. val)
- else return val
- where
- go :: Int -> a -> IO (a,Int,Bool)
- go shift val = do
- byte <- getByte bh
- let !byteVal = fromIntegral (clearBit byte 7) :: a
- let !val' = val .|. (byteVal `unsafeShiftL` shift)
- let !more = testBit byte 7
- let !shift' = shift+7
- if more
- then go (shift') val'
- else do
- let !signed = testBit byte 6
- return (val',shift',signed)
--- -----------------------------------------------------------------------------
--- Primitive Word writes
+class GBinary (f :: * -> *) where
+ gput :: f a -> Put ()
+ gget :: Get (f a)
-instance Binary Word8 where
- put_ bh !w = putWord8 bh w
- get = getWord8
+instance GBinary U1 where
+ gput U1 = return ()
+ gget = return U1
-instance Binary Word16 where
- put_ = putULEB128
- get = getULEB128
+instance GBinary a => GBinary (M1 i c a) where
+ gput (M1 x) = gput x
+ gget = M1 <$> gget
-instance Binary Word32 where
- put_ = putULEB128
- get = getULEB128
+instance Binary a => GBinary (K1 i a) where
+ gput (K1 x) = put x
+ gget = K1 <$> get
-instance Binary Word64 where
- put_ = putULEB128
- get = getULEB128
+instance (GBinary a, GBinary b) => GBinary (a :*: b) where
+ gput (x :*: y) = gput x >> gput y
+ gget = (:*:) <$> gget <*> gget
--- -----------------------------------------------------------------------------
--- Primitive Int writes
+instance (GSumBinary (a :+: b)) => GBinary (a :+: b) where
+ gput = gsput (maxIndex @(a :+: b))
+ gget = gsget =<< get
-instance Binary Int8 where
- put_ h w = put_ h (fromIntegral w :: Word8)
- get h = do w <- get h; return $! (fromIntegral (w::Word8))
+class KnownNat (SumSize f) => GSumBinary (f :: * -> *) where
+ type SumSize f :: Nat
+ gsput :: Int8 -> f a -> Put ()
+ gsget :: Int8 -> Get (f a)
-instance Binary Int16 where
- put_ = putSLEB128
- get = getSLEB128
+instance (GSumBinary a, GSumBinary b, KnownNat (SumSize (a :+: b)))
+ => GSumBinary (a :+: b) where
+ type SumSize (a :+: b) = SumSize a + SumSize b
+ gsput n (L1 x) = gsput (n - sumSize @b) x
+ gsput n (R1 x) = gsput n x
+ gsget n | n <= maxIndex @a = L1 <$> gsget n
+ | otherwise = R1 <$> gsget (n - sumSize @a)
-instance Binary Int32 where
- put_ = putSLEB128
- get = getSLEB128
+instance GBinary (M1 i c a) => GSumBinary (M1 i c a) where
+ type SumSize (M1 i c a) = 1
+ gsput n x = put n >> gput x
+ gsget _ = gget
-instance Binary Int64 where
- put_ h w = putSLEB128 h w
- get h = getSLEB128 h
+sumSize :: forall f. GSumBinary f => Int8
+sumSize = fromIntegral $ natVal' (proxy# :: Proxy# (SumSize f))
+maxIndex :: forall f. GSumBinary f => Int8
+maxIndex = sumSize @f - 1
+
+-- -----------------------------------------------------------------------------
+-- Standard instances
-- -----------------------------------------------------------------------------
--- Instances for standard types
instance Binary () where
- put_ _ () = return ()
- get _ = return ()
+ put () = return ()
+ get = return ()
instance Binary Bool where
- put_ bh b = putByte bh (fromIntegral (fromEnum b))
- get bh = do x <- getWord8 bh; return $! (toEnum (fromIntegral x))
+ put b = putByte (fromIntegral (fromEnum b))
+ get = do x <- getWord8; return $! (toEnum (fromIntegral x))
instance Binary Char where
- put_ bh c = put_ bh (fromIntegral (ord c) :: Word32)
- get bh = do x <- get bh; return $! (chr (fromIntegral (x :: Word32)))
+ put c = put (fromIntegral (ord c) :: Word32)
+ get = do x <- get; return $! chr (fromIntegral (x :: Word32))
instance Binary Int where
- put_ bh i = put_ bh (fromIntegral i :: Int64)
- get bh = do
- x <- get bh
- return $! (fromIntegral (x :: Int64))
+ put = putInt
+ get = getInt
instance Binary a => Binary [a] where
- put_ bh l = do
- let len = length l
- put_ bh len
- mapM_ (put_ bh) l
- get bh = do
- len <- get bh :: IO Int -- Int is variable length encoded so only
- -- one byte for small lists.
- let loop 0 = return []
- loop n = do a <- get bh; as <- loop (n-1); return (a:as)
- loop len
+ put xs = do
+ put (length xs)
+ mapM_ put xs
+ get = do
+ loop =<< (get :: Get Int)
+ where
+ loop 0 = return []
+ loop n = (:) <$> get <*> loop (pred n)
instance (Ix a, Binary a, Binary b) => Binary (Array a b) where
- put_ bh arr = do
- put_ bh $ bounds arr
- put_ bh $ elems arr
- get bh = do
- bounds <- get bh
- xs <- get bh
+ put arr = do
+ put $ bounds arr
+ put $ elems arr
+ get = do
+ bounds <- get
+ xs <- get
return $ listArray bounds xs
instance (Binary a, Binary b) => Binary (a,b) where
- put_ bh (a,b) = do put_ bh a; put_ bh b
- get bh = do a <- get bh
- b <- get bh
- return (a,b)
+ put (a,b) = do put a; put b
+ get = do a <- get
+ b <- get
+ return (a,b)
instance (Binary a, Binary b, Binary c) => Binary (a,b,c) where
- put_ bh (a,b,c) = do put_ bh a; put_ bh b; put_ bh c
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- return (a,b,c)
+ put (a,b,c) = do put a; put b; put c
+ get = do a <- get
+ b <- get
+ c <- get
+ return (a,b,c)
instance (Binary a, Binary b, Binary c, Binary d) => Binary (a,b,c,d) where
- put_ bh (a,b,c,d) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- return (a,b,c,d)
+ put (a,b,c,d) = do put a; put b; put c; put d
+ get = do a <- get
+ b <- get
+ c <- get
+ d <- get
+ return (a,b,c,d)
instance (Binary a, Binary b, Binary c, Binary d, Binary e) => Binary (a,b,c,d, e) where
- put_ bh (a,b,c,d, e) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e;
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- e <- get bh
- return (a,b,c,d,e)
+ put (a,b,c,d, e) = do put a; put b; put c; put d; put e;
+ get = do a <- get
+ b <- get
+ c <- get
+ d <- get
+ e <- get
+ return (a,b,c,d,e)
instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f) => Binary (a,b,c,d, e, f) where
- put_ bh (a,b,c,d, e, f) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e; put_ bh f;
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- e <- get bh
- f <- get bh
- return (a,b,c,d,e,f)
+ put (a,b,c,d, e, f) = do put a; put b; put c; put d; put e; put f;
+ get = do a <- get
+ b <- get
+ c <- get
+ d <- get
+ e <- get
+ f <- get
+ return (a,b,c,d,e,f)
instance (Binary a, Binary b, Binary c, Binary d, Binary e, Binary f, Binary g) => Binary (a,b,c,d,e,f,g) where
- put_ bh (a,b,c,d,e,f,g) = do put_ bh a; put_ bh b; put_ bh c; put_ bh d; put_ bh e; put_ bh f; put_ bh g
- get bh = do a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
- e <- get bh
- f <- get bh
- g <- get bh
- return (a,b,c,d,e,f,g)
+ put (a,b,c,d,e,f,g) = do put a; put b; put c; put d; put e; put f; put g
+ get = do a <- get
+ b <- get
+ c <- get
+ d <- get
+ e <- get
+ f <- get
+ g <- get
+ return (a,b,c,d,e,f,g)
instance Binary a => Binary (Maybe a) where
- put_ bh Nothing = putByte bh 0
- put_ bh (Just a) = do putByte bh 1; put_ bh a
- get bh = do h <- getWord8 bh
- case h of
- 0 -> return Nothing
- _ -> do x <- get bh; return (Just x)
+ put Nothing = putByte 0
+ put (Just a) = do putByte 1; put a
+ get = do h <- getWord8
+ case h of
+ 0 -> return Nothing
+ _ -> do x <- get; return (Just x)
instance (Binary a, Binary b) => Binary (Either a b) where
- put_ bh (Left a) = do putByte bh 0; put_ bh a
- put_ bh (Right b) = do putByte bh 1; put_ bh b
- get bh = do h <- getWord8 bh
- case h of
- 0 -> do a <- get bh ; return (Left a)
- _ -> do b <- get bh ; return (Right b)
+ put (Left a) = do putByte 0; put a
+ put (Right b) = do putByte 1; put b
+ get = do h <- getWord8
+ case h of
+ 0 -> do a <- get; return (Left a)
+ _ -> do b <- get; return (Right b)
instance Binary UTCTime where
- put_ bh u = do put_ bh (utctDay u)
- put_ bh (utctDayTime u)
- get bh = do day <- get bh
- dayTime <- get bh
- return $ UTCTime { utctDay = day, utctDayTime = dayTime }
+ put u = do put (utctDay u)
+ put (utctDayTime u)
+ get = do day <- get
+ dayTime <- get
+ return $ UTCTime { utctDay = day, utctDayTime = dayTime }
instance Binary Day where
- put_ bh d = put_ bh (toModifiedJulianDay d)
- get bh = do i <- get bh
- return $ ModifiedJulianDay { toModifiedJulianDay = i }
+ put d = put (toModifiedJulianDay d)
+ get = do i <- get
+ return $ ModifiedJulianDay { toModifiedJulianDay = i }
instance Binary DiffTime where
- put_ bh dt = put_ bh (toRational dt)
- get bh = do r <- get bh
- return $ fromRational r
+ put dt = put (toRational dt)
+ get = do r <- get
+ return $ fromRational r
-{-
-Finally - a reasonable portable Integer instance.
+instance (Binary a) => Binary (Ratio a) where
+ put (a :% b) = do put a; put b
+ get = do a <- get; b <- get; return (a :% b)
+-- -----------------------------------------------------------------------------
+-- Primitives
+-- -----------------------------------------------------------------------------
+
+instance Binary Word8 where
+ put !w = putWord8 w
+ get = getWord8
+
+instance Binary Word16 where
+ put = putULEB128
+ get = getULEB128
+
+instance Binary Word32 where
+ put = putULEB128
+ get = getULEB128
+
+instance Binary Word64 where
+ put = putULEB128
+ get = getULEB128
+
+instance Binary Int8 where
+ put w = put (fromIntegral w :: Word8)
+ get = do w <- get; return $! (fromIntegral (w :: Word8))
+
+instance Binary Int16 where
+ put = putSLEB128
+ get = getSLEB128
+
+instance Binary Int32 where
+ put = putSLEB128
+ get = getSLEB128
+
+instance Binary Int64 where
+ put = putSLEB128
+ get = getSLEB128
+
+instance Binary FastString where
+ put = putAFastString
+ get = getAFastString
+
+instance Binary (Bin a) where
+ get = getBin
+ put = putBin
+
+instance Binary Strict.ByteString where
+ put = putByteString
+ get = getByteString
+
+instance Binary Lazy.ByteString where
+ put = put . Lazy.toStrict
+ get = Lazy.fromStrict <$> get
+
+-- -----------------------------------------------------------------------------
+-- Integer
+-- -----------------------------------------------------------------------------
+
+{-
We used to encode values in the Int32 range as such,
falling back to a string of all things. In either case
we stored a tag byte to discriminate between the two cases.
@@ -699,29 +400,29 @@ The instance is used for in Binary Integer and Binary Rational in basicTypes/Lit
-}
instance Binary Integer where
- put_ bh i
+ put i
| i >= lo64 && i <= hi64 = do
- putWord8 bh 0
- put_ bh (fromIntegral i :: Int64)
+ putWord8 0
+ put (fromIntegral i :: Int64)
| otherwise = do
if i < 0
- then putWord8 bh 1
- else putWord8 bh 2
- put_ bh (unroll $ abs i)
+ then putWord8 1
+ else putWord8 2
+ put (unroll $ abs i)
where
lo64 = fromIntegral (minBound :: Int64)
hi64 = fromIntegral (maxBound :: Int64)
- get bh = do
- int_kind <- getWord8 bh
+ get = do
+ int_kind <- getWord8
case int_kind of
- 0 -> fromIntegral <$!> (get bh :: IO Int64)
+ 0 -> fromIntegral <$!> (get :: Get Int64)
-- Large integer
- 1 -> negate <$!> getInt
- 2 -> getInt
+ 1 -> negate <$!> getI
+ 2 -> getI
_ -> panic "Binary Integer - Invalid byte"
where
- getInt :: IO Integer
- getInt = roll <$!> (get bh :: IO [Word8])
+ getI :: Get Integer
+ getI = roll <$!> (get :: Get [Word8])
unroll :: Integer -> [Word8]
unroll = unfoldr step
@@ -734,135 +435,58 @@ roll = foldl' unstep 0 . reverse
where
unstep a b = a `shiftL` 8 .|. fromIntegral b
-
- {-
- -- This code is currently commented out.
- -- See https://gitlab.haskell.org/ghc/ghc/issues/3379#note_104346 for
- -- discussion.
-
- put_ bh (S# i#) = do putByte bh 0; put_ bh (I# i#)
- put_ bh (J# s# a#) = do
- putByte bh 1
- put_ bh (I# s#)
- let sz# = sizeofByteArray# a# -- in *bytes*
- put_ bh (I# sz#) -- in *bytes*
- putByteArray bh a# sz#
-
- get bh = do
- b <- getByte bh
- case b of
- 0 -> do (I# i#) <- get bh
- return (S# i#)
- _ -> do (I# s#) <- get bh
- sz <- get bh
- (BA a#) <- getByteArray bh sz
- return (J# s# a#)
-
-putByteArray :: BinHandle -> ByteArray# -> Int# -> IO ()
-putByteArray bh a s# = loop 0#
- where loop n#
- | n# ==# s# = return ()
- | otherwise = do
- putByte bh (indexByteArray a n#)
- loop (n# +# 1#)
-
-getByteArray :: BinHandle -> Int -> IO ByteArray
-getByteArray bh (I# sz) = do
- (MBA arr) <- newByteArray sz
- let loop n
- | n ==# sz = return ()
- | otherwise = do
- w <- getByte bh
- writeByteArray arr n w
- loop (n +# 1#)
- loop 0#
- freezeByteArray arr
- -}
-
-{-
-data ByteArray = BA ByteArray#
-data MBA = MBA (MutableByteArray# RealWorld)
-
-newByteArray :: Int# -> IO MBA
-newByteArray sz = IO $ \s ->
- case newByteArray# sz s of { (# s, arr #) ->
- (# s, MBA arr #) }
-
-freezeByteArray :: MutableByteArray# RealWorld -> IO ByteArray
-freezeByteArray arr = IO $ \s ->
- case unsafeFreezeByteArray# arr s of { (# s, arr #) ->
- (# s, BA arr #) }
-
-writeByteArray :: MutableByteArray# RealWorld -> Int# -> Word8 -> IO ()
-writeByteArray arr i (W8# w) = IO $ \s ->
- case writeWord8Array# arr i w s of { s ->
- (# s, () #) }
-
-indexByteArray :: ByteArray# -> Int# -> Word8
-indexByteArray a# n# = W8# (indexWord8Array# a# n#)
-
--}
-instance (Binary a) => Binary (Ratio a) where
- put_ bh (a :% b) = do put_ bh a; put_ bh b
- get bh = do a <- get bh; b <- get bh; return (a :% b)
-
--- Instance uses fixed-width encoding to allow inserting
--- Bin placeholders in the stream.
-instance Binary (Bin a) where
- put_ bh (BinPtr i) = putWord32 bh (fromIntegral i :: Word32)
- get bh = do i <- getWord32 bh; return (BinPtr (fromIntegral (i :: Word32)))
-
-- -----------------------------------------------------------------------------
--- Instances for Data.Typeable stuff
+-- Data.Typeable instances
+-- -----------------------------------------------------------------------------
instance Binary TyCon where
- put_ bh tc = do
- put_ bh (tyConPackage tc)
- put_ bh (tyConModule tc)
- put_ bh (tyConName tc)
- put_ bh (tyConKindArgs tc)
- put_ bh (tyConKindRep tc)
- get bh =
- mkTyCon <$> get bh <*> get bh <*> get bh <*> get bh <*> get bh
+ put tc = do
+ put (tyConPackage tc)
+ put (tyConModule tc)
+ put (tyConName tc)
+ put (tyConKindArgs tc)
+ put (tyConKindRep tc)
+ get =
+ mkTyCon <$> get <*> get <*> get <*> get <*> get
instance Binary VecCount where
- put_ bh = putByte bh . fromIntegral . fromEnum
- get bh = toEnum . fromIntegral <$> getByte bh
+ put = putByte . fromIntegral . fromEnum
+ get = toEnum . fromIntegral <$> getByte
instance Binary VecElem where
- put_ bh = putByte bh . fromIntegral . fromEnum
- get bh = toEnum . fromIntegral <$> getByte bh
+ put = putByte . fromIntegral . fromEnum
+ get = toEnum . fromIntegral <$> getByte
instance Binary RuntimeRep where
- put_ bh (VecRep a b) = putByte bh 0 >> put_ bh a >> put_ bh b
- put_ bh (TupleRep reps) = putByte bh 1 >> put_ bh reps
- put_ bh (SumRep reps) = putByte bh 2 >> put_ bh reps
- put_ bh LiftedRep = putByte bh 3
- put_ bh UnliftedRep = putByte bh 4
- put_ bh IntRep = putByte bh 5
- put_ bh WordRep = putByte bh 6
- put_ bh Int64Rep = putByte bh 7
- put_ bh Word64Rep = putByte bh 8
- put_ bh AddrRep = putByte bh 9
- put_ bh FloatRep = putByte bh 10
- put_ bh DoubleRep = putByte bh 11
+ put (VecRep a b) = putByte 0 >> put a >> put b
+ put (TupleRep reps) = putByte 1 >> put reps
+ put (SumRep reps) = putByte 2 >> put reps
+ put LiftedRep = putByte 3
+ put UnliftedRep = putByte 4
+ put IntRep = putByte 5
+ put WordRep = putByte 6
+ put Int64Rep = putByte 7
+ put Word64Rep = putByte 8
+ put AddrRep = putByte 9
+ put FloatRep = putByte 10
+ put DoubleRep = putByte 11
#if __GLASGOW_HASKELL__ >= 807
- put_ bh Int8Rep = putByte bh 12
- put_ bh Word8Rep = putByte bh 13
- put_ bh Int16Rep = putByte bh 14
- put_ bh Word16Rep = putByte bh 15
+ put Int8Rep = putByte 12
+ put Word8Rep = putByte 13
+ put Int16Rep = putByte 14
+ put Word16Rep = putByte 15
#endif
#if __GLASGOW_HASKELL__ >= 809
- put_ bh Int32Rep = putByte bh 16
- put_ bh Word32Rep = putByte bh 17
+ put Int32Rep = putByte 16
+ put Word32Rep = putByte 17
#endif
- get bh = do
- tag <- getByte bh
+ get = do
+ tag <- getByte
case tag of
- 0 -> VecRep <$> get bh <*> get bh
- 1 -> TupleRep <$> get bh
- 2 -> SumRep <$> get bh
+ 0 -> VecRep <$> get <*> get
+ 1 -> TupleRep <$> get
+ 2 -> SumRep <$> get
3 -> pure LiftedRep
4 -> pure UnliftedRep
5 -> pure IntRep
@@ -885,65 +509,65 @@ instance Binary RuntimeRep where
_ -> fail "Binary.putRuntimeRep: invalid tag"
instance Binary KindRep where
- put_ bh (KindRepTyConApp tc k) = putByte bh 0 >> put_ bh tc >> put_ bh k
- put_ bh (KindRepVar bndr) = putByte bh 1 >> put_ bh bndr
- put_ bh (KindRepApp a b) = putByte bh 2 >> put_ bh a >> put_ bh b
- put_ bh (KindRepFun a b) = putByte bh 3 >> put_ bh a >> put_ bh b
- put_ bh (KindRepTYPE r) = putByte bh 4 >> put_ bh r
- put_ bh (KindRepTypeLit sort r) = putByte bh 5 >> put_ bh sort >> put_ bh r
-
- get bh = do
- tag <- getByte bh
+ put (KindRepTyConApp tc k) = putByte 0 >> put tc >> put k
+ put (KindRepVar bndr) = putByte 1 >> put bndr
+ put (KindRepApp a b) = putByte 2 >> put a >> put b
+ put (KindRepFun a b) = putByte 3 >> put a >> put b
+ put (KindRepTYPE r) = putByte 4 >> put r
+ put (KindRepTypeLit sort r) = putByte 5 >> put sort >> put r
+
+ get = do
+ tag <- getByte
case tag of
- 0 -> KindRepTyConApp <$> get bh <*> get bh
- 1 -> KindRepVar <$> get bh
- 2 -> KindRepApp <$> get bh <*> get bh
- 3 -> KindRepFun <$> get bh <*> get bh
- 4 -> KindRepTYPE <$> get bh
- 5 -> KindRepTypeLit <$> get bh <*> get bh
+ 0 -> KindRepTyConApp <$> get <*> get
+ 1 -> KindRepVar <$> get
+ 2 -> KindRepApp <$> get <*> get
+ 3 -> KindRepFun <$> get <*> get
+ 4 -> KindRepTYPE <$> get
+ 5 -> KindRepTypeLit <$> get <*> get
_ -> fail "Binary.putKindRep: invalid tag"
instance Binary TypeLitSort where
- put_ bh TypeLitSymbol = putByte bh 0
- put_ bh TypeLitNat = putByte bh 1
- get bh = do
- tag <- getByte bh
+ put TypeLitSymbol = putByte 0
+ put TypeLitNat = putByte 1
+ get = do
+ tag <- getByte
case tag of
0 -> pure TypeLitSymbol
1 -> pure TypeLitNat
_ -> fail "Binary.putTypeLitSort: invalid tag"
-putTypeRep :: BinHandle -> TypeRep a -> IO ()
+putTypeRep :: TypeRep a -> Put ()
-- Special handling for TYPE, (->), and RuntimeRep due to recursive kind
-- relations.
-- See Note [Mutually recursive representations of primitive types]
-putTypeRep bh rep
+putTypeRep rep
| Just HRefl <- rep `eqTypeRep` (typeRep :: TypeRep Type)
- = put_ bh (0 :: Word8)
-putTypeRep bh (Con' con ks) = do
- put_ bh (1 :: Word8)
- put_ bh con
- put_ bh ks
-putTypeRep bh (App f x) = do
- put_ bh (2 :: Word8)
- putTypeRep bh f
- putTypeRep bh x
-putTypeRep bh (Fun arg res) = do
- put_ bh (3 :: Word8)
- putTypeRep bh arg
- putTypeRep bh res
-
-getSomeTypeRep :: BinHandle -> IO SomeTypeRep
-getSomeTypeRep bh = do
- tag <- get bh :: IO Word8
+ = put (0 :: Word8)
+putTypeRep (Con' con ks) = do
+ put (1 :: Word8)
+ put con
+ put ks
+putTypeRep (App f x) = do
+ put (2 :: Word8)
+ putTypeRep f
+ putTypeRep x
+putTypeRep (Fun arg res) = do
+ put (3 :: Word8)
+ putTypeRep arg
+ putTypeRep res
+
+getSomeTypeRep :: Get SomeTypeRep
+getSomeTypeRep = do
+ tag <- get :: Get Word8
case tag of
0 -> return $ SomeTypeRep (typeRep :: TypeRep Type)
- 1 -> do con <- get bh :: IO TyCon
- ks <- get bh :: IO [SomeTypeRep]
+ 1 -> do con <- get :: Get TyCon
+ ks <- get :: Get [SomeTypeRep]
return $ SomeTypeRep $ mkTrCon con ks
- 2 -> do SomeTypeRep f <- getSomeTypeRep bh
- SomeTypeRep x <- getSomeTypeRep bh
+ 2 -> do SomeTypeRep f <- getSomeTypeRep
+ SomeTypeRep x <- getSomeTypeRep
case typeRepKind f of
Fun arg res ->
case arg `eqTypeRep` typeRepKind x of
@@ -960,8 +584,8 @@ getSomeTypeRep bh = do
[ " Applied type: " ++ show f
, " To argument: " ++ show x
]
- 3 -> do SomeTypeRep arg <- getSomeTypeRep bh
- SomeTypeRep res <- getSomeTypeRep bh
+ 3 -> do SomeTypeRep arg <- getSomeTypeRep
+ SomeTypeRep res <- getSomeTypeRep
if
| App argkcon _ <- typeRepKind arg
, App reskcon _ <- typeRepKind res
@@ -979,9 +603,9 @@ getSomeTypeRep bh = do
++ map (" "++) info
instance Typeable a => Binary (TypeRep (a :: k)) where
- put_ = putTypeRep
- get bh = do
- SomeTypeRep rep <- getSomeTypeRep bh
+ put = putTypeRep
+ get = do
+ SomeTypeRep rep <- getSomeTypeRep
case rep `eqTypeRep` expected of
Just HRefl -> pure rep
Nothing -> fail $ unlines
@@ -992,431 +616,273 @@ instance Typeable a => Binary (TypeRep (a :: k)) where
where expected = typeRep :: TypeRep a
instance Binary SomeTypeRep where
- put_ bh (SomeTypeRep rep) = putTypeRep bh rep
+ put (SomeTypeRep rep) = putTypeRep rep
get = getSomeTypeRep
-- -----------------------------------------------------------------------------
--- Lazy reading/writing
-
-lazyPut :: Binary a => BinHandle -> a -> IO ()
-lazyPut bh a = do
- -- output the obj with a ptr to skip over it:
- pre_a <- tellBin bh
- put_ bh pre_a -- save a slot for the ptr
- put_ bh a -- dump the object
- q <- tellBin bh -- q = ptr to after object
- putAt bh pre_a q -- fill in slot before a with ptr to q
- seekBin bh q -- finally carry on writing at q
-
-lazyGet :: Binary a => BinHandle -> IO a
-lazyGet bh = do
- p <- get bh -- a BinPtr
- p_a <- tellBin bh
- a <- unsafeInterleaveIO $ do
- -- NB: Use a fresh off_r variable in the child thread, for thread
- -- safety.
- off_r <- newFastMutInt
- getAt bh { _off_r = off_r } p_a
- seekBin bh p -- skip over the object for now
- return a
-
--- -----------------------------------------------------------------------------
--- UserData
+-- Other instances
-- -----------------------------------------------------------------------------
--- | Information we keep around during interface file
--- serialization/deserialization. Namely we keep the functions for serializing
--- and deserializing 'Name's and 'FastString's. We do this because we actually
--- use serialization in two distinct settings,
---
--- * When serializing interface files themselves
---
--- * When computing the fingerprint of an IfaceDecl (which we computing by
--- hashing its Binary serialization)
---
--- These two settings have different needs while serializing Names:
---
--- * Names in interface files are serialized via a symbol table (see Note
--- [Symbol table representation of names] in BinIface).
---
--- * During fingerprinting a binding Name is serialized as the OccName and a
--- non-binding Name is serialized as the fingerprint of the thing they
--- represent. See Note [Fingerprinting IfaceDecls] for further discussion.
---
-data UserData =
- UserData {
- -- for *deserialising* only:
- ud_get_name :: BinHandle -> IO Name,
- ud_get_fs :: BinHandle -> IO FastString,
-
- -- for *serialising* only:
- ud_put_nonbinding_name :: BinHandle -> Name -> IO (),
- -- ^ serialize a non-binding 'Name' (e.g. a reference to another
- -- binding).
- ud_put_binding_name :: BinHandle -> Name -> IO (),
- -- ^ serialize a binding 'Name' (e.g. the name of an IfaceDecl)
- ud_put_fs :: BinHandle -> FastString -> IO ()
- }
-
-newReadState :: (BinHandle -> IO Name) -- ^ how to deserialize 'Name's
- -> (BinHandle -> IO FastString)
- -> UserData
-newReadState get_name get_fs
- = UserData { ud_get_name = get_name,
- ud_get_fs = get_fs,
- ud_put_nonbinding_name = undef "put_nonbinding_name",
- ud_put_binding_name = undef "put_binding_name",
- ud_put_fs = undef "put_fs"
- }
-
-newWriteState :: (BinHandle -> Name -> IO ())
- -- ^ how to serialize non-binding 'Name's
- -> (BinHandle -> Name -> IO ())
- -- ^ how to serialize binding 'Name's
- -> (BinHandle -> FastString -> IO ())
- -> UserData
-newWriteState put_nonbinding_name put_binding_name put_fs
- = UserData { ud_get_name = undef "get_name",
- ud_get_fs = undef "get_fs",
- ud_put_nonbinding_name = put_nonbinding_name,
- ud_put_binding_name = put_binding_name,
- ud_put_fs = put_fs
- }
-
-noUserData :: a
-noUserData = undef "UserData"
-
-undef :: String -> a
-undef s = panic ("Binary.UserData: no " ++ s)
-
----------------------------------------------------------
--- The Dictionary
----------------------------------------------------------
-
-type Dictionary = Array Int FastString -- The dictionary
- -- Should be 0-indexed
-
-putDictionary :: BinHandle -> Int -> UniqFM (Int,FastString) -> IO ()
-putDictionary bh sz dict = do
- put_ bh sz
- mapM_ (putFS bh) (elems (array (0,sz-1) (nonDetEltsUFM dict)))
- -- It's OK to use nonDetEltsUFM here because the elements have indices
- -- that array uses to create order
-
-getDictionary :: BinHandle -> IO Dictionary
-getDictionary bh = do
- sz <- get bh
- elems <- sequence (take sz (repeat (getFS bh)))
- return (listArray (0,sz-1) elems)
-
----------------------------------------------------------
--- The Symbol Table
----------------------------------------------------------
-
--- On disk, the symbol table is an array of IfExtName, when
--- reading it in we turn it into a SymbolTable.
-
-type SymbolTable = Array Int Name
-
----------------------------------------------------------
--- Reading and writing FastStrings
----------------------------------------------------------
-
-putFS :: BinHandle -> FastString -> IO ()
-putFS bh fs = putBS bh $ bytesFS fs
-
-getFS :: BinHandle -> IO FastString
-getFS bh = do
- l <- get bh :: IO Int
- getPrim bh l (\src -> pure $! mkFastStringBytes src l )
-
-putBS :: BinHandle -> ByteString -> IO ()
-putBS bh bs =
- BS.unsafeUseAsCStringLen bs $ \(ptr, l) -> do
- put_ bh l
- putPrim bh l (\op -> BS.memcpy op (castPtr ptr) l)
-
-getBS :: BinHandle -> IO ByteString
-getBS bh = do
- l <- get bh :: IO Int
- BS.create l $ \dest -> do
- getPrim bh l (\src -> BS.memcpy dest src l)
-
-instance Binary ByteString where
- put_ bh f = putBS bh f
- get bh = getBS bh
-
-instance Binary FastString where
- put_ bh f =
- case getUserData bh of
- UserData { ud_put_fs = put_fs } -> put_fs bh f
-
- get bh =
- case getUserData bh of
- UserData { ud_get_fs = get_fs } -> get_fs bh
-
--- Here to avoid loop
instance Binary LeftOrRight where
- put_ bh CLeft = putByte bh 0
- put_ bh CRight = putByte bh 1
+ put CLeft = putByte 0
+ put CRight = putByte 1
- get bh = do { h <- getByte bh
- ; case h of
- 0 -> return CLeft
- _ -> return CRight }
+ get = do { h <- getByte
+ ; case h of
+ 0 -> return CLeft
+ _ -> return CRight }
instance Binary PromotionFlag where
- put_ bh NotPromoted = putByte bh 0
- put_ bh IsPromoted = putByte bh 1
+ put NotPromoted = putByte 0
+ put IsPromoted = putByte 1
- get bh = do
- n <- getByte bh
+ get = do
+ n <- getByte
case n of
0 -> return NotPromoted
1 -> return IsPromoted
_ -> fail "Binary(IsPromoted): fail)"
instance Binary Fingerprint where
- put_ h (Fingerprint w1 w2) = do put_ h w1; put_ h w2
- get h = do w1 <- get h; w2 <- get h; return (Fingerprint w1 w2)
+ put (Fingerprint w1 w2) = do put w1; put w2
+ get = do w1 <- get ; w2 <- get; return (Fingerprint w1 w2)
instance Binary FunctionOrData where
- put_ bh IsFunction = putByte bh 0
- put_ bh IsData = putByte bh 1
- get bh = do
- h <- getByte bh
+ put IsFunction = putByte 0
+ put IsData = putByte 1
+ get = do
+ h <- getByte
case h of
0 -> return IsFunction
1 -> return IsData
_ -> panic "Binary FunctionOrData"
instance Binary TupleSort where
- put_ bh BoxedTuple = putByte bh 0
- put_ bh UnboxedTuple = putByte bh 1
- put_ bh ConstraintTuple = putByte bh 2
- get bh = do
- h <- getByte bh
+ put BoxedTuple = putByte 0
+ put UnboxedTuple = putByte 1
+ put ConstraintTuple = putByte 2
+ get = do
+ h <- getByte
case h of
0 -> do return BoxedTuple
1 -> do return UnboxedTuple
_ -> do return ConstraintTuple
instance Binary Activation where
- put_ bh NeverActive = do
- putByte bh 0
- put_ bh AlwaysActive = do
- putByte bh 1
- put_ bh (ActiveBefore src aa) = do
- putByte bh 2
- put_ bh src
- put_ bh aa
- put_ bh (ActiveAfter src ab) = do
- putByte bh 3
- put_ bh src
- put_ bh ab
- get bh = do
- h <- getByte bh
+ put NeverActive = do
+ putByte 0
+ put AlwaysActive = do
+ putByte 1
+ put (ActiveBefore src aa) = do
+ putByte 2
+ put src
+ put aa
+ put (ActiveAfter src ab) = do
+ putByte 3
+ put src
+ put ab
+ get = do
+ h <- getByte
case h of
0 -> do return NeverActive
1 -> do return AlwaysActive
- 2 -> do src <- get bh
- aa <- get bh
+ 2 -> do src <- get
+ aa <- get
return (ActiveBefore src aa)
- _ -> do src <- get bh
- ab <- get bh
+ _ -> do src <- get
+ ab <- get
return (ActiveAfter src ab)
instance Binary InlinePragma where
- put_ bh (InlinePragma s a b c d) = do
- put_ bh s
- put_ bh a
- put_ bh b
- put_ bh c
- put_ bh d
-
- get bh = do
- s <- get bh
- a <- get bh
- b <- get bh
- c <- get bh
- d <- get bh
+ put (InlinePragma s a b c d) = do
+ put s
+ put a
+ put b
+ put c
+ put d
+
+ get = do
+ s <- get
+ a <- get
+ b <- get
+ c <- get
+ d <- get
return (InlinePragma s a b c d)
instance Binary RuleMatchInfo where
- put_ bh FunLike = putByte bh 0
- put_ bh ConLike = putByte bh 1
- get bh = do
- h <- getByte bh
+ put FunLike = putByte 0
+ put ConLike = putByte 1
+ get = do
+ h <- getByte
if h == 1 then return ConLike
else return FunLike
instance Binary InlineSpec where
- put_ bh NoUserInline = putByte bh 0
- put_ bh Inline = putByte bh 1
- put_ bh Inlinable = putByte bh 2
- put_ bh NoInline = putByte bh 3
-
- get bh = do h <- getByte bh
- case h of
- 0 -> return NoUserInline
- 1 -> return Inline
- 2 -> return Inlinable
- _ -> return NoInline
+ put NoUserInline = putByte 0
+ put Inline = putByte 1
+ put Inlinable = putByte 2
+ put NoInline = putByte 3
+
+ get = do h <- getByte
+ case h of
+ 0 -> return NoUserInline
+ 1 -> return Inline
+ 2 -> return Inlinable
+ _ -> return NoInline
instance Binary RecFlag where
- put_ bh Recursive = do
- putByte bh 0
- put_ bh NonRecursive = do
- putByte bh 1
- get bh = do
- h <- getByte bh
+ put Recursive = do
+ putByte 0
+ put NonRecursive = do
+ putByte 1
+ get = do
+ h <- getByte
case h of
0 -> do return Recursive
_ -> do return NonRecursive
instance Binary OverlapMode where
- put_ bh (NoOverlap s) = putByte bh 0 >> put_ bh s
- put_ bh (Overlaps s) = putByte bh 1 >> put_ bh s
- put_ bh (Incoherent s) = putByte bh 2 >> put_ bh s
- put_ bh (Overlapping s) = putByte bh 3 >> put_ bh s
- put_ bh (Overlappable s) = putByte bh 4 >> put_ bh s
- get bh = do
- h <- getByte bh
+ put (NoOverlap s) = putByte 0 >> put s
+ put (Overlaps s) = putByte 1 >> put s
+ put (Incoherent s) = putByte 2 >> put s
+ put (Overlapping s) = putByte 3 >> put s
+ put (Overlappable s) = putByte 4 >> put s
+ get = do
+ h <- getByte
case h of
- 0 -> (get bh) >>= \s -> return $ NoOverlap s
- 1 -> (get bh) >>= \s -> return $ Overlaps s
- 2 -> (get bh) >>= \s -> return $ Incoherent s
- 3 -> (get bh) >>= \s -> return $ Overlapping s
- 4 -> (get bh) >>= \s -> return $ Overlappable s
+ 0 -> NoOverlap <$> get
+ 1 -> Overlaps <$> get
+ 2 -> Incoherent <$> get
+ 3 -> Overlapping <$> get
+ 4 -> Overlappable <$> get
_ -> panic ("get OverlapMode" ++ show h)
instance Binary OverlapFlag where
- put_ bh flag = do put_ bh (overlapMode flag)
- put_ bh (isSafeOverlap flag)
- get bh = do
- h <- get bh
- b <- get bh
+ put flag = do put (overlapMode flag)
+ put (isSafeOverlap flag)
+ get = do
+ h <- get
+ b <- get
return OverlapFlag { overlapMode = h, isSafeOverlap = b }
instance Binary FixityDirection where
- put_ bh InfixL = do
- putByte bh 0
- put_ bh InfixR = do
- putByte bh 1
- put_ bh InfixN = do
- putByte bh 2
- get bh = do
- h <- getByte bh
- case h of
- 0 -> do return InfixL
- 1 -> do return InfixR
- _ -> do return InfixN
-
-instance Binary Fixity where
- put_ bh (Fixity src aa ab) = do
- put_ bh src
- put_ bh aa
- put_ bh ab
- get bh = do
- src <- get bh
- aa <- get bh
- ab <- get bh
+ put InfixL = do
+ putByte 0
+ put InfixR = do
+ putByte 1
+ put InfixN = do
+ putByte 2
+ get = do
+ h <- getByte
+ case h of
+ 0 -> do return InfixL
+ 1 -> do return InfixR
+ _ -> do return InfixN
+
+instance Binary BasicTypes.Fixity where
+ put (Fixity src aa ab) = do
+ put src
+ put aa
+ put ab
+ get = do
+ src <- get
+ aa <- get
+ ab <- get
return (Fixity src aa ab)
instance Binary WarningTxt where
- put_ bh (WarningTxt s w) = do
- putByte bh 0
- put_ bh s
- put_ bh w
- put_ bh (DeprecatedTxt s d) = do
- putByte bh 1
- put_ bh s
- put_ bh d
-
- get bh = do
- h <- getByte bh
+ put (WarningTxt s w) = do
+ putByte 0
+ put s
+ put w
+ put (DeprecatedTxt s d) = do
+ putByte 1
+ put s
+ put d
+
+ get = do
+ h <- getByte
case h of
- 0 -> do s <- get bh
- w <- get bh
+ 0 -> do s <- get
+ w <- get
return (WarningTxt s w)
- _ -> do s <- get bh
- d <- get bh
+ _ -> do s <- get
+ d <- get
return (DeprecatedTxt s d)
instance Binary StringLiteral where
- put_ bh (StringLiteral st fs) = do
- put_ bh st
- put_ bh fs
- get bh = do
- st <- get bh
- fs <- get bh
+ put (StringLiteral st fs) = do
+ put st
+ put fs
+ get = do
+ st <- get
+ fs <- get
return (StringLiteral st fs)
instance Binary a => Binary (Located a) where
- put_ bh (L l x) = do
- put_ bh l
- put_ bh x
+ put (L l x) = do
+ put l
+ put x
- get bh = do
- l <- get bh
- x <- get bh
+ get = do
+ l <- get
+ x <- get
return (L l x)
instance Binary RealSrcSpan where
- put_ bh ss = do
- put_ bh (srcSpanFile ss)
- put_ bh (srcSpanStartLine ss)
- put_ bh (srcSpanStartCol ss)
- put_ bh (srcSpanEndLine ss)
- put_ bh (srcSpanEndCol ss)
-
- get bh = do
- f <- get bh
- sl <- get bh
- sc <- get bh
- el <- get bh
- ec <- get bh
- return (mkRealSrcSpan (mkRealSrcLoc f sl sc)
- (mkRealSrcLoc f el ec))
+ put ss = do
+ put (srcSpanFile ss)
+ put (srcSpanStartLine ss)
+ put (srcSpanStartCol ss)
+ put (srcSpanEndLine ss)
+ put (srcSpanEndCol ss)
+
+ get = do f <- get
+ sl <- get
+ sc <- get
+ el <- get
+ ec <- get
+ return (mkRealSrcSpan (mkRealSrcLoc f sl sc)
+ (mkRealSrcLoc f el ec))
instance Binary SrcSpan where
- put_ bh (RealSrcSpan ss) = do
- putByte bh 0
- put_ bh ss
+ put (RealSrcSpan ss) = do
+ putByte 0
+ put ss
- put_ bh (UnhelpfulSpan s) = do
- putByte bh 1
- put_ bh s
+ put (UnhelpfulSpan s) = do
+ putByte 1
+ put s
- get bh = do
- h <- getByte bh
+ get = do
+ h <- getByte
case h of
- 0 -> do ss <- get bh
+ 0 -> do ss <- get
return (RealSrcSpan ss)
- _ -> do s <- get bh
+ _ -> do s <- get
return (UnhelpfulSpan s)
instance Binary Serialized where
- put_ bh (Serialized the_type bytes) = do
- put_ bh the_type
- put_ bh bytes
- get bh = do
- the_type <- get bh
- bytes <- get bh
+ put (Serialized the_type bytes) = do
+ put the_type
+ put bytes
+ get = do
+ the_type <- get
+ bytes <- get
return (Serialized the_type bytes)
instance Binary SourceText where
- put_ bh NoSourceText = putByte bh 0
- put_ bh (SourceText s) = do
- putByte bh 1
- put_ bh s
+ put NoSourceText = putByte 0
+ put (SourceText s) = do
+ putByte 1
+ put s
- get bh = do
- h <- getByte bh
+ get = do
+ h <- getByte
case h of
0 -> return NoSourceText
1 -> do
- s <- get bh
+ s <- get
return (SourceText s)
_ -> panic $ "Binary SourceText:" ++ show h