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