packages feed

ghc-hie-0.0.0: src/GHC/Iface/Ext/Binary/Header.hs

module GHC.Iface.Ext.Binary.Header (
  extractSourceFileName
, HieHeader
, readHieFileHeader
) where

import Control.Monad
import Data.Word
import Data.ByteString (ByteString, pack)
import Data.ByteString.Internal (w2c)
import GHC.Settings.Utils (maybeRead)

import GHC.Iface.Ext.Binary.Utils

hieMagic :: [Word8]
hieMagic = [72,73,69]

hieMagicLen :: Int
hieMagicLen = 3

newline :: Word8
newline = 10

extractSourceFileName :: ReadBinHandle -> IO FilePath
extractSourceFileName bh0 = do
  advance bh0 hieMagicLen
  skipLine
  skipLine
  advance bh0 8
  get @FilePath bh0
  where
    skipLine :: IO ()
    skipLine = do
      c <- get @Word8 bh0
      if c == newline
      then return ()
      else skipLine

type HieHeader = (Integer, ByteString)

readHieFileHeader :: FilePath -> ReadBinHandle -> IO HieHeader
readHieFileHeader file bh0 = do
  magic <- replicateM hieMagicLen (get bh0)
  version <- map w2c <$> takeLine
  case maybeRead version of
    Nothing -> do
      fail $ "readHieFileHeader: hieVersion isn't an Integer: " <> show version
    Just hieVersion -> do
      ghcVersion <- pack <$> takeLine
      when (magic /= hieMagic) . fail $ unwords [
          "readHieFileHeader: headers don't match for file:"
        , file
        , "Expected"
        , show hieMagic
        , "but got", show magic
        ]
      return (hieVersion, ghcVersion)
  where
    takeLine :: IO [Word8]
    takeLine = reverse <$> loop []
      where
        loop :: [Word8] -> IO [Word8]
        loop acc = do
          c <- get @Word8 bh0
          if c == newline
          then return acc
          else loop (c : acc)