content: {-
    Copyright (c) Meta Platforms, Inc. and affiliates.
    All rights reserved.
  
    This source code is licensed under the BSD-style license found in the
    LICENSE file in the root directory of this source tree.
  -}
  
  -- | Fingerprints for schema versioning.
  --
  -- Doesn't need to be cryptographically secure, but does need to be
  -- robust against accidental collisions.
  
  module Glean.Angle.Hash
    ( Hash
    , hash0
    , hashString
    , hashByteString
    , hashBinary
    , hashFingerprint
    ) where
  
  import qualified Data.ByteString as B
  import qualified Data.ByteString.Lazy as LB
  import Data.ByteString.Unsafe (unsafeUseAsCStringLen)
  import Data.Binary (Binary)
  import qualified Data.Binary as Binary
  import Data.Hashable
  import Foreign (castPtr)
  import GHC.Fingerprint as GHC
  import System.IO.Unsafe ( unsafeDupablePerformIO )
  
  -- efficient MD5 hash
  type Hash = GHC.Fingerprint
  
  hash0 :: Hash
  hash0 = GHC.fingerprint0
  
  hashString :: String -> Hash
  hashString = GHC.fingerprintString
  
  hashByteString :: B.ByteString -> Hash
  hashByteString bs = unsafeDupablePerformIO $ do
    unsafeUseAsCStringLen bs $ \(ptr, len) ->
      GHC.fingerprintData (castPtr ptr) (fromIntegral len)
  
  hashBinary :: Binary a => a -> Hash
  hashBinary = hashByteString . LB.toStrict . Binary.encode
  
  -- | For building Hashable instances. Avoiding an orphan instance by
  -- making this a function instead.
  hashFingerprint :: Int -> Hash -> Int
  hashFingerprint salt (GHC.Fingerprint _ w) = hashWithSalt salt w
  