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.
  -}
  
  {-# LANGUAGE CPP #-}
  module Thrift.Protocol.Binary.Internal
    ( binaryFloat, binaryDouble, getBuffer
    ) where
  
  #if __GLASGOW_HASKELL__ == 804
  import Thrift.Binary.Parser (getWord32be)
  #endif
  import Thrift.Binary.Parser as P
  import Data.ByteString (ByteString)
  import Foreign.Marshal.Alloc
  import Foreign.Storable as F
  import Foreign.Ptr
  import System.IO.Unsafe
  
  {-# INLINE toFloat #-}
  toFloat
    :: (Floating f, Storable f, Storable a)
    => a
    -> f
  toFloat a =
    unsafeDupablePerformIO $ alloca $ \ptr ->
      poke ptr a >> F.peek (castPtr ptr)
  
  {-# INLINE binaryFloat #-}
  binaryFloat :: Parser Float
  binaryFloat = toFloat <$> getWord32be
  
  {-# INLINE binaryDouble #-}
  binaryDouble :: Parser Double
  binaryDouble = toFloat <$> getWord64be
  
  {-# INLINE getBuffer #-}
  -- | Parse a ByteString given a length parser and a copy function.
  -- Note: The copy function *must* copy the input, otherwise this is unsafe
  -- because the result is a slice of the input which may be a memory buffer that
  -- is owned by C++. We also want to eliminate references to the input so that it
  -- can get GC'd
  getBuffer :: Integral len => Parser len -> (ByteString -> a) -> Parser a
  getBuffer getLength copy = do
    len <- getLength
    buf <- P.getByteString $ fromIntegral len
    return $! copy buf
  