-- | Contains functions for constructing and working with foreign simdjson instances.

module Data.Hermes.SIMDJSON.Wrapper
  ( allocaArray
  , allocaArrayIter
  , allocaObject
  , allocaObjectIter
  , allocaValue
  , mkSIMDParser
  , mkSIMDDocument
  , mkSIMDPaddedStr
  , withInputBuffer
  )
  where

import           Data.ByteString (ByteString)
import qualified Data.ByteString.Unsafe as Unsafe
import           Data.Maybe (fromMaybe)
import           Control.Exception (mask_)
import qualified Foreign.ForeignPtr as F
import qualified Foreign.Marshal.Alloc as F
import qualified Foreign.Ptr as F

import           Data.Hermes.SIMDJSON.Bindings
  ( deleteDocumentImpl
  , deleteInputImpl
  , makeDocumentImpl
  , makeInputImpl
  , parserDestroy
  , parserInit
  )
import           Data.Hermes.SIMDJSON.Types

mkSIMDParser :: Maybe Int -> IO (F.ForeignPtr SIMDParser)
mkSIMDParser :: Maybe Int -> IO (ForeignPtr SIMDParser)
mkSIMDParser Maybe Int
mCap = forall a. IO a -> IO a
mask_ forall a b. (a -> b) -> a -> b
$ do
  let maxCap :: Int
maxCap = Int
4000000000; -- 4GB
  Ptr SIMDParser
ptr <- CSize -> IO (Ptr SIMDParser)
parserInit forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Enum a => Int -> a
toEnum forall a b. (a -> b) -> a -> b
$ forall a. a -> Maybe a -> a
fromMaybe Int
maxCap Maybe Int
mCap
  forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
F.newForeignPtr FunPtr (Ptr SIMDParser -> IO ())
parserDestroy Ptr SIMDParser
ptr
{-# INLINE mkSIMDParser #-}

mkSIMDDocument :: IO (F.ForeignPtr SIMDDocument)
mkSIMDDocument :: IO (ForeignPtr SIMDDocument)
mkSIMDDocument = forall a. IO a -> IO a
mask_ forall a b. (a -> b) -> a -> b
$ do
  Ptr SIMDDocument
ptr <- IO (Ptr SIMDDocument)
makeDocumentImpl
  forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
F.newForeignPtr FunPtr (Ptr SIMDDocument -> IO ())
deleteDocumentImpl Ptr SIMDDocument
ptr
{-# INLINE mkSIMDDocument #-}

mkSIMDPaddedStr :: ByteString -> IO (F.ForeignPtr PaddedString)
mkSIMDPaddedStr :: ByteString -> IO (ForeignPtr PaddedString)
mkSIMDPaddedStr ByteString
input = forall a. IO a -> IO a
mask_ forall a b. (a -> b) -> a -> b
$
  forall a. ByteString -> (CStringLen -> IO a) -> IO a
Unsafe.unsafeUseAsCStringLen ByteString
input forall a b. (a -> b) -> a -> b
$ \(Ptr CChar
cstr, Int
len) -> do
    Ptr PaddedString
ptr <- Ptr CChar -> CSize -> IO (Ptr PaddedString)
makeInputImpl Ptr CChar
cstr (forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
len)
    forall a. FinalizerPtr a -> Ptr a -> IO (ForeignPtr a)
F.newForeignPtr FunPtr (Ptr PaddedString -> IO ())
deleteInputImpl Ptr PaddedString
ptr
{-# INLINE mkSIMDPaddedStr #-}

withInputBuffer :: ByteString -> (InputBuffer -> IO a) -> IO a
withInputBuffer :: forall a. ByteString -> (InputBuffer -> IO a) -> IO a
withInputBuffer ByteString
bs InputBuffer -> IO a
f = do
  ForeignPtr PaddedString
pStr <- ByteString -> IO (ForeignPtr PaddedString)
mkSIMDPaddedStr ByteString
bs
  forall a b. ForeignPtr a -> (Ptr a -> IO b) -> IO b
F.withForeignPtr ForeignPtr PaddedString
pStr forall a b. (a -> b) -> a -> b
$ InputBuffer -> IO a
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. Ptr PaddedString -> InputBuffer
InputBuffer
{-# INLINE withInputBuffer #-}

allocaValue :: (Value -> IO a) -> IO a
allocaValue :: forall a. (Value -> IO a) -> IO a
allocaValue Value -> IO a
f = forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
24 forall a b. (a -> b) -> a -> b
$ \Ptr JSONValue
val -> Value -> IO a
f (Ptr JSONValue -> Value
Value Ptr JSONValue
val)
{-# INLINE allocaValue #-}

allocaObject :: (Object -> IO a) -> IO a
allocaObject :: forall a. (Object -> IO a) -> IO a
allocaObject Object -> IO a
f = forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
24 forall a b. (a -> b) -> a -> b
$ \Ptr JSONObject
objPtr -> Object -> IO a
f (Ptr JSONObject -> Object
Object Ptr JSONObject
objPtr)
{-# INLINE allocaObject #-}

allocaArray :: (Array -> IO a) -> IO a
allocaArray :: forall a. (Array -> IO a) -> IO a
allocaArray Array -> IO a
f = forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
24 forall a b. (a -> b) -> a -> b
$ \Ptr JSONArray
arr -> Array -> IO a
f (Ptr JSONArray -> Array
Array Ptr JSONArray
arr)
{-# INLINE allocaArray #-}

allocaArrayIter :: (ArrayIter -> IO a) -> IO a
allocaArrayIter :: forall a. (ArrayIter -> IO a) -> IO a
allocaArrayIter ArrayIter -> IO a
f = forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
24 forall a b. (a -> b) -> a -> b
$ \Ptr JSONArrayIter
iter -> ArrayIter -> IO a
f (Ptr JSONArrayIter -> ArrayIter
ArrayIter Ptr JSONArrayIter
iter)
{-# INLINE allocaArrayIter #-}

allocaObjectIter :: (ObjectIter -> IO a) -> IO a
allocaObjectIter :: forall a. (ObjectIter -> IO a) -> IO a
allocaObjectIter ObjectIter -> IO a
f = forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
24 forall a b. (a -> b) -> a -> b
$ \Ptr JSONObjectIter
iter -> ObjectIter -> IO a
f (Ptr JSONObjectIter -> ObjectIter
ObjectIter Ptr JSONObjectIter
iter)
{-# INLINE allocaObjectIter #-}

allocaBytes :: Int -> (F.Ptr a -> IO b) -> IO b
allocaBytes :: forall a b. Int -> (Ptr a -> IO b) -> IO b
allocaBytes Int
size Ptr a -> IO b
action = forall a b. Int -> (Ptr a -> IO b) -> IO b
F.allocaBytes Int
size Ptr a -> IO b
action
{-# INLINE allocaBytes #-}