packages feed

glean-0.2.0.0: glean/angle/Glean/Angle/Hash.hs

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