{- 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 GeneralizedNewtypeDeriving #-} {-# LANGUAGE TemplateHaskell #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Foreign.CPP.HsStruct.Types ( StorableContainer(..) -- * HsRange , HsRange(..) , HsStringPiece , withByteStringAsHsStringPiece , withTextAsHsStringPiece -- * HsMaybe , HsMaybe(..) -- * HsOption , HsOption(..) -- * HsEither , HsEither(..) , peekHsEitherWith -- * HsPair , HsPair(..) , peekHsPairWith -- * HsStdTuple , HsStdTuple(..) -- * HsString , HsString(..) , HsByteString(..) , HsText(..) , HsLenientText(..) -- * HsArray , HsArray(..) , HsArrayStorable(..) , HsList(..) -- * HsMap , HsMap(..) , HsIntMap(..) , HsHashMap(..) , HsObject(..) , HsHashSet(..) -- * HsJSON , HsJSON(..) ) where import Control.DeepSeq (NFData) import Data.Aeson (Value(..)) import Data.ByteString (ByteString, packCStringLen) import Data.ByteString.Unsafe (unsafeUseAsCStringLen) import Data.Hashable (Hashable, hashWithSalt) import Data.Text (Text) import qualified Data.Text.Encoding as Text (encodeUtf8) import Data.HashMap.Strict (HashMap) import qualified Data.HashSet as HashSet import Data.IntMap.Strict (IntMap) import Data.Map.Strict (Map) import Data.Scientific (fromFloatDigits, floatingOrInteger, toBoundedInteger, toRealFloat) import Data.Vector (Vector, generateM) import qualified Data.Vector.Storable as VS import qualified Data.Vector as Vector import Foreign hiding (void) import Foreign.C import qualified Data.HashMap.Strict as HashMap import qualified Data.IntMap.Strict as IntMap import qualified Data.Map.Strict as Map import Foreign.CPP.Addressable hiding (alignment, sizeOf) import qualified Foreign.CPP.Addressable as Addressable import Foreign.CPP.HsStruct.HsArray import Foreign.CPP.HsStruct.HsSet import Foreign.CPP.HsStruct.HsMap import Foreign.CPP.HsStruct.HsOption import Foreign.CPP.HsStruct.HsStdTuple import Foreign.CPP.HsStruct.Utils import Foreign.CPP.Marshallable.TH import Mangle.TH import Util.Aeson import Util.FFI import Util.Text (cStringLenToText, cStringLenToTextLenient) #include #include #include #include #include -- | An abstraction over storable containers. The elements will be marshaled or -- interpreted by given function. The element type must be 'Addressable' -- (with 'sizeOf' and 'alignment' defined) in order to use 'peekWith' and -- 'pokeWith'. -- -- Compared with creating a newtype for the element type, it will avoid -- * duplicate identical implementation of 'sizeOf' and 'pokeWith' -- * a trivial newtype unwrapping -- * an unsafe 'castPtr' in some cases -- while introduce some risk of using wrong marshalers. class StorableContainer f where -- | Given a function to read each element, reads the whole container from -- the specified memory location peekWith :: Addressable a => (Ptr a -> IO b) -> Ptr (f a) -> IO (f b) -- | Given a function to write each element, writes the whole container to -- the specified memory location pokeWith :: Addressable a => (Ptr a -> b -> IO ()) -> Ptr (f a) -> f b -> IO () -- The default way to read and write a container. Require 'peek'/'poke' for -- element type being implemented to use 'peek'/'poke' for the whole container. instance {-# OVERLAPPABLE #-} (Addressable1 f, StorableContainer f, Addressable a, Storable a) => Storable (f a) where sizeOf = sizeOf1 alignment = alignment1 peek = peekWith peek poke = pokeWith poke peekElemOffWith :: forall a b. Addressable a => (Ptr a -> IO b) -> Ptr a -> Int -> IO b peekElemOffWith f p i = f $ p `plusPtr` (i * offset) where offset = Addressable.sizeOf (undefined :: a) notPokeable :: String -> a notPokeable t = error $ "HsStruct." <> t <> " is not HS_POKEABLE" -- HsRange -------------------------------------------------------------------- data HsRange a n = HsRange (Ptr a) n instance Integral n => Storable (HsRange a n) where sizeOf _ = #{size DummyHsRange} alignment _ = #{alignment DummyHsRange} peek p = do (a :: Ptr a) <- #{peek DummyHsRange, a} p (n :: CSize) <- #{peek DummyHsRange, n} p return $ HsRange a $ fromIntegral n poke p (HsRange a n) = do #{poke DummyHsRange, a} p a #{poke DummyHsRange, n} p (fromIntegral n :: CSize) type HsStringPiece = HsRange CChar Int $(mangle "void ctorHsStringPiece(HsRange*, const char*, size_t)" [d| foreign import ccall unsafe c_constructHsStringPiece :: Ptr HsStringPiece -> CString -> Word -> IO () |]) $(mangle "HsStringPiece* newHsStringPiece(const char*, size_t)" [d| foreign import ccall unsafe c_newHsStringPiece :: CString -> Word -> IO (Ptr HsStringPiece) |]) instance Constructible HsStringPiece where newValue (HsRange str len) = castPtr <$> c_newHsStringPiece str (fromIntegral len) constructValue p (HsRange str len) = c_constructHsStringPiece (castPtr p) str (fromIntegral len) instance Addressable HsStringPiece withByteStringAsHsStringPiece :: ByteString -> (HsStringPiece -> IO res) -> IO res withByteStringAsHsStringPiece b act = unsafeUseAsCStringLen b $ \cstrlen -> act (uncurry HsRange cstrlen) withTextAsHsStringPiece :: Text -> (HsStringPiece -> IO res) -> IO res withTextAsHsStringPiece b = withByteStringAsHsStringPiece (Text.encodeUtf8 b) -- HsMaybe -------------------------------------------------------------------- newtype HsMaybe a = HsMaybe { hsMaybe :: Maybe a } instance Addressable1 HsMaybe where sizeOf1 _ = #{size DummyHsMaybe} alignment1 _ = #{alignment DummyHsMaybe} instance Addressable (HsMaybe a) where sizeOf = sizeOf1 alignment = alignment1 instance StorableContainer HsMaybe where pokeWith = notPokeable "HsMaybe" peekWith f p = do ptr <- #{peek DummyHsMaybe, ptr} p HsMaybe <$> maybePeek f ptr -- HsString ------------------------------------------------------------------- newtype HsString = HsString { hsString :: String } $(mangle "void ctorHsString(HsString*, const char*, size_t)}" [d| foreign import ccall unsafe c_constructHsString :: Ptr HsString -> CString -> Word -> IO () |]) $(mangle "HsString* newHsString(const char*, size_t)}" [d| foreign import ccall unsafe c_newHsString :: CString -> Word -> IO (Ptr HsString) |]) instance Addressable HsString instance Storable HsString where sizeOf _ = #{size HsString} alignment _ = #{alignment HsString} poke = notPokeable "HsString" peek p = fmap HsString $ peekCStringLen =<< peekStrLen p peekStrLen :: Ptr a -> IO CStringLen peekStrLen p = do (str :: CString) <- #{peek HsString, str} p (len :: CSize) <- #{peek HsString, len} p return (str, fromIntegral len) newStrImpl :: ByteString -> IO (Ptr a) newStrImpl bs = castPtr <$> (unsafeUseAsCStringLen bs $ \(str, len) -> c_newHsString str (fromIntegral len)) constructStrImpl :: Ptr a -> ByteString -> IO () constructStrImpl p bs = unsafeUseAsCStringLen bs $ \(str, len) -> c_constructHsString (castPtr p) str (fromIntegral len) -- HsText --------------------------------------------------------------- newtype HsText = HsText { hsText :: Text } instance Addressable HsText where sizeOf _ = #{size HsString} alignment _ = #{alignment HsString} instance Constructible HsText where newValue (HsText txt) = newStrImpl (Text.encodeUtf8 txt) constructValue p (HsText txt) = constructStrImpl (castPtr p) (Text.encodeUtf8 txt) instance Storable HsText where sizeOf _ = #{size HsString} alignment _ = #{alignment HsString} poke = error "HsStruct.HsText: poke not implemented" peek p = fmap HsText $ uncurry cStringLenToText =<< peekStrLen p instance Eq HsText where (HsText a) == (HsText b) = a == b instance Hashable HsText where hashWithSalt i (HsText a) = hashWithSalt i a -- HsEither ------------------------------------------------------------------- #{enum HsEitherTag, HsEitherTag , hs_Left = HS_LEFT , hs_Right = HS_RIGHT } newtype HsEitherTag = HsEitherTag #{type HsEitherTag} deriving (Eq, Storable) newtype HsEither a b = HsEither { hsEither :: Either a b } deriving NFData $(mangle "void* newHsEither(HsEitherTag, void*)}" [d| foreign import ccall unsafe c_newHsEither :: HsEitherTag -> Ptr c -> IO (Ptr (HsEither a b)) |]) instance Addressable1 (HsEither a) where sizeOf1 _ = #{size DummyHsEither} alignment1 _ = #{alignment DummyHsEither} instance Addressable (HsEither a b) where sizeOf = sizeOf1 alignment = alignment1 instance Storable a => StorableContainer (HsEither a) where pokeWith = notPokeable "HsEither" peekWith = peekHsEitherWith peek peekHsEitherWith :: (Ptr a -> IO x) -> (Ptr b -> IO y) -> Ptr (HsEither a b) -> IO (HsEither x y) peekHsEitherWith peekLeft peekRight p = do isLeft <- #{peek DummyHsEither, isLeft} p :: IO CChar if toBool isLeft then do ptr <- #{peek DummyHsEither, left} p HsEither . Left <$> peekLeft ptr else do ptr <- #{peek DummyHsEither, right} p HsEither . Right <$> peekRight ptr instance (Constructible a, Constructible b) => Constructible (HsEither a b) where newValue (HsEither (Left a)) = do p_left <- newValue a c_newHsEither hs_Left p_left newValue (HsEither (Right b)) = do p_right <- newValue b c_newHsEither hs_Right p_right constructValue p (HsEither (Left a)) = do p_left <- newValue a #{poke DummyHsEither, isLeft} p (fromIntegral (1::Int) :: CBool) #{poke DummyHsEither, left} p p_left constructValue p (HsEither (Right b)) = do #{poke DummyHsEither, isLeft} p (fromIntegral (0::Int) :: CBool) p_right <- newValue b #{poke DummyHsEither, right} p p_right -- HsPair --------------------------------------------------------------------- newtype HsPair a b = HsPair { hsPair :: (a, b) } instance Addressable1 (HsPair a) where sizeOf1 _ = #{size DummyHsPair} alignment1 _ = #{alignment DummyHsPair} instance Addressable (HsPair a b) where sizeOf = sizeOf1 alignment = alignment1 instance Storable a => StorableContainer (HsPair a) where pokeWith = notPokeable "HsPair" peekWith = peekHsPairWith peek peekHsPairWith :: (Ptr a -> IO x) -> (Ptr b -> IO y) -> Ptr (HsPair a b) -> IO (HsPair x y) peekHsPairWith peekFirst peekSecond p = do ptr_a <- #{peek DummyHsPair, fst_} p fs <- peekFirst ptr_a ptr_b <- #{peek DummyHsPair, snd_} p sn <- peekSecond ptr_b return $ HsPair (fs, sn) -- HsByteString --------------------------------------------------------------- newtype HsByteString = HsByteString { hsByteString :: ByteString } deriving NFData instance Addressable HsByteString where sizeOf _ = #{size HsString} alignment _ = #{alignment HsString} instance Constructible HsByteString where newValue (HsByteString bs) = newStrImpl bs constructValue p (HsByteString bs) = constructStrImpl (castPtr p) bs instance Storable HsByteString where sizeOf _ = #{size HsString} alignment _ = #{alignment HsString} poke = notPokeable "HsByteString" peek p = fmap HsByteString $ packCStringLen =<< peekStrLen p instance Eq HsByteString where (HsByteString a) == (HsByteString b) = a == b instance Hashable HsByteString where hashWithSalt i (HsByteString a) = hashWithSalt i a -- HsLenientText -------------------------------------------------------------- newtype HsLenientText = HsLenientText { hsLenientText :: Text } deriving (Eq, Hashable) instance Addressable HsLenientText instance Constructible HsLenientText where newValue (HsLenientText txt) = newStrImpl (Text.encodeUtf8 txt) constructValue p (HsLenientText txt) = constructStrImpl (castPtr p) (Text.encodeUtf8 txt) instance Storable HsLenientText where sizeOf _ = #{size HsString} alignment _ = #{alignment HsString} poke = notPokeable "HsLenientText" peek p = fmap HsLenientText $ uncurry cStringLenToTextLenient =<< peekStrLen p -- HsArray newtype HsArray a = HsArray { hsArray :: Vector a } instance Addressable1 HsArray where sizeOf1 _ = #{size DummyHsArray} alignment1 _ = #{alignment DummyHsArray} instance Addressable (HsArray a) where sizeOf = sizeOf1 alignment = alignment1 instance StorableContainer HsArray where pokeWith = notPokeable "HsArray" peekWith f p = do (a, n) <- peekDataSize p fmap HsArray . generateM n $ \i -> peekElemOffWith f a i -- | 'HsArrayStorable' is 'HsArray' with a more efficient -- representation, which can be passed back out to C++ without copying -- using Vector.Storable.unsafeWith. newtype HsArrayStorable a = HsArrayStorable { hsArrayStorable :: VS.Vector a } instance Storable a => Storable (HsArrayStorable a) where sizeOf _ = #{size DummyHsArray} alignment _ = #{alignment DummyHsArray} poke = notPokeable "HsArrayStorable" peek p = do (a, n) <- peekDataSize p arr <- mallocForeignPtrArray n unsafeWithForeignPtr arr $ \parr -> copyBytes parr a (n * sizeOf (undefined :: a)) return (HsArrayStorable (VS.unsafeFromForeignPtr0 arr n)) -- HsList newtype HsList a = HsList { hsList :: [a] } instance Addressable1 HsList where sizeOf1 _ = #{size DummyHsArray} alignment1 _ = #{alignment DummyHsArray} instance Addressable (HsList a) where sizeOf = sizeOf1 alignment = alignment1 instance StorableContainer HsList where pokeWith = notPokeable "HsList" peekWith f p = do (a, n) <- peekDataSize p let go !i !acc | i < 0 = return acc | otherwise = do e <- peekElemOffWith f a i go (i-1) (e:acc) HsList <$> go (n-1) [] peekDataSize :: Ptr b -> IO (Ptr a, Int) peekDataSize p = do (a :: Ptr a) <- #{peek DummyHsArray, a} p (n :: CSize) <- #{peek DummyHsArray, n} p return (a, fromIntegral n) -- HsSet newtype HsHashSet a = HsHashSet -- Contains a List as a transport for the internal datatype that may not be -- immediately hashable in haskell (i.e. CLong is not hashable, but the end -- type of Int is) { hsHashSet :: HashSet.HashSet a } instance Addressable1 HsHashSet where sizeOf1 = setSizeOf alignment1 = setAlignment instance Addressable (HsHashSet a) where sizeOf = sizeOf1 alignment = alignment1 instance (Addressable a, Eq a, Hashable a, Storable a) => Storable (HsHashSet a) where sizeOf = sizeOf1 alignment = alignment1 poke = notPokeable "HsHashSet" peek p = HsHashSet <$> peekSetWith HashSet.empty HashSet.insert peek p {-# INLINE peekSetWith #-} peekSetWith :: (Addressable a) => s -> (k -> s -> s) -> (Ptr a -> IO k) -> Ptr b -> IO s peekSetWith empty insert f p = do (a :: Ptr a) <- #{peek DummyHsSet, keys} p (n :: Int) <- (fromIntegral :: CSize -> Int) <$> #{peek DummyHsSet, n} p let go !i !hs | i >= n = return hs | otherwise = do k <- peekElemOffWith f a i go (i + 1) $ insert k hs go 0 empty setSizeOf, setAlignment :: a -> Int setSizeOf _ = #{size DummyHsSet} setAlignment _ = #{alignment DummyHsSet} -- HsMap newtype HsMap k v = HsMap { hsMap :: Map k v } instance Addressable1 (HsMap k) where sizeOf1 = mapSizeOf alignment1 = mapAlignment instance Addressable (HsMap k v) where sizeOf = sizeOf1 alignment = alignment1 instance (Addressable k, Ord k, Storable k) => StorableContainer (HsMap k) where pokeWith = notPokeable "HsMap" peekWith f p = HsMap <$> peekMapWith Map.empty Map.insert peek f p newtype HsIntMap v = HsIntMap { hsIntMap :: IntMap v } instance Addressable1 HsIntMap where sizeOf1 = mapSizeOf alignment1 = mapAlignment instance Addressable (HsIntMap v) where sizeOf = sizeOf1 alignment = alignment1 instance StorableContainer HsIntMap where pokeWith = notPokeable "HsIntMap" peekWith f p = HsIntMap <$> peekMapWith IntMap.empty IntMap.insert peek f p newtype HsHashMap k v = HsHashMap { hsHashMap :: HashMap k v } instance Addressable1 (HsHashMap k) where sizeOf1 = mapSizeOf alignment1 = mapAlignment instance Addressable (HsHashMap k v) where sizeOf = sizeOf1 alignment = alignment1 instance (Addressable k, Eq k, Hashable k, Storable k) => StorableContainer (HsHashMap k) where pokeWith = notPokeable "HsHashMap" peekWith f p = HsHashMap <$> peekMapWith HashMap.empty HashMap.insert peek f p newtype HsObject v = HsObject { hsObject :: KeyMap v } instance Addressable1 HsObject where sizeOf1 = mapSizeOf alignment1 = mapAlignment instance Addressable (HsObject v) where sizeOf = sizeOf1 alignment = alignment1 instance StorableContainer HsObject where pokeWith = notPokeable "HsObject" peekWith f p = HsObject <$> peekMapWith emptyKeyMap insertKeyMap fk f p where fk = fmap (keyFromText . hsText) . peek mapSizeOf, mapAlignment :: a -> Int mapSizeOf _ = #{size DummyHsObject} mapAlignment _ = #{alignment DummyHsObject} foreign import ccall unsafe "common_hs_ctorHsObjectJSON" c_constructHsObjectJSON :: Ptr (HsObject HsJSON) -> Ptr (HsArray HsText) -> Ptr (HsArray HsJSON) -> IO () {-# INLINE peekMapWith #-} peekMapWith :: (Addressable a, Addressable b) => m -> (k -> v -> m -> m) -> (Ptr a -> IO k) -> (Ptr b -> IO v) -> Ptr c -> IO m peekMapWith empty insert fk fv p = do size <- (fromIntegral :: CSize -> Int) <$> #{peek DummyHsObject, n} p keys <- #{peek DummyHsObject, keys} p values <- #{peek DummyHsObject, values} p let go !i !hm | i >= size = return hm | otherwise = do k <- peekElemOffWith fk keys i v <- peekElemOffWith fv values i go (i+1) $ insert k v hm go 0 empty -- HsJSON newtype HsJSON = HsJSON { hsJSON :: Value } instance Addressable HsJSON instance Storable HsJSON where sizeOf _ = #{size HsJSON} alignment _ = #{alignment HsJSON} poke = notPokeable "HsJSON" peek p = do (t :: CInt) <- #{peek HsJSON, type} p #{let json_type t = "%d", static_cast(HsJSON::Type::t)} HsJSON <$> case t of #{json_type Null} -> return Null #{json_type Bool} -> Bool . toBool <$> peekIntegral #{json_type Integral} -> Number . fromIntegral <$> peekIntegral #{json_type Real} -> Number . fromFloatDigits <$> (#{peek HsJSON, real} p :: IO CDouble) #{json_type String} -> String . hsText <$> #{peek HsJSON, string} p #{json_type Array} -> Array . fmap hsJSON . hsArray <$> #{peek HsJSON, array} p #{json_type Object} -> Object . fmap hsJSON . hsObject <$> #{peek HsJSON, object} p _ -> error "HsStruct.HsJSON: invalid HsJSON::Type" where peekIntegral = #{peek HsJSON, integral} p :: IO CLong $(mangle "void ctorHsJSONNull(HsJSON*)" [d| foreign import ccall unsafe c_constructHsJSONNull :: Ptr HsJSON -> IO () |]) $(mangle "void ctorHsJSONBool(HsJSON*, bool)" [d| foreign import ccall unsafe c_constructHsJSONBool :: Ptr HsJSON -> CBool -> IO () |]) $(mangle "void ctorHsJSONInt(HsJSON*, int64_t)" [d| foreign import ccall unsafe c_constructHsJSONInt :: Ptr HsJSON -> CLong -> IO () |]) $(mangle "void ctorHsJSONDouble(HsJSON*, double)" [d| foreign import ccall unsafe c_constructHsJSONDouble :: Ptr HsJSON -> CDouble -> IO () |]) $(mangle "void ctorHsJSONString(HsJSON*, HsString*)" [d| foreign import ccall unsafe c_constructHsJSONString :: Ptr HsJSON -> Ptr HsText -> IO () |]) $(mangle "void ctorHsJSONArray(HsJSON*, HsArray*)" [d| foreign import ccall unsafe c_constructHsJSONArray :: Ptr HsJSON -> Ptr (HsArray HsJSON) -> IO () |]) $(mangle "void ctorHsJSONObject(HsJSON*, HsMap*)" [d| foreign import ccall unsafe c_constructHsJSONObject :: Ptr HsJSON -> Ptr (HsObject HsJSON) -> IO () |]) -- Derive Marshallables first $(deriveMarshallableUnsafe "HsMaybeInt" [t| HsMaybe Int |]) $(deriveMarshallableUnsafe "HsMaybeDouble" [t| HsMaybe Double |]) $(deriveMarshallableUnsafe "HsMaybeString" [t| HsMaybe HsByteString |]) $(deriveMarshallableUnsafe "HsMaybeString" [t| HsMaybe HsText |]) $(deriveMarshallableUnsafe "HsMaybeString" [t| HsMaybe HsLenientText |]) $(deriveMarshallableUnsafe "HsEitherStringInt" [t| HsEither HsText Int |]) $(deriveMarshallableUnsafe "HsEitherStringDouble" [t| HsEither HsText Double |]) $(deriveMarshallableUnsafe "HsEitherStringString" [t| HsEither HsText HsByteString |]) $(deriveMarshallableUnsafe "HsEitherStringString" [t| HsEither HsText HsText |]) $(deriveMarshallableUnsafe "HsEitherStringInt" [t| HsEither HsLenientText Int |]) $(deriveMarshallableUnsafe "HsEitherStringDouble" [t| HsEither HsLenientText Double |]) $(deriveMarshallableUnsafe "HsEitherStringString" [t| HsEither HsLenientText HsByteString |]) $(deriveMarshallableUnsafe "HsEitherStringString" [t| HsEither HsLenientText HsLenientText |]) $(deriveMarshallableUnsafe "HsEitherStringArrayInt" [t| HsEither HsText (HsList Int) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayDouble" [t| HsEither HsText (HsList Double) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayString" [t| HsEither HsText (HsList HsByteString) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayString" [t| HsEither HsText (HsList HsText) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayInt" [t| HsEither HsLenientText (HsList Int) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayDouble" [t| HsEither HsLenientText (HsList Double) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayString" [t| HsEither HsLenientText (HsList HsByteString) |]) $(deriveMarshallableUnsafe "HsEitherStringArrayString" [t| HsEither HsLenientText (HsList HsLenientText) |]) instance Assignable (HsEither HsText Int) instance Assignable (HsEither HsText Double) instance Assignable (HsEither HsText HsByteString) instance Assignable (HsEither HsText HsText) $(deriveMarshallableUnsafe "HsString" [t| HsString |]) $(deriveMarshallableUnsafe "HsString" [t| HsByteString |]) $(deriveMarshallableUnsafe "HsString" [t| HsLenientText |]) $(deriveMarshallableUnsafe "HsString" [t| HsText |]) instance Assignable HsText instance Assignable HsByteString instance Assignable HsLenientText $(deriveMarshallableUnsafe "HsStringPiece" [t| HsStringPiece |]) $(deriveMarshallableUnsafe "HsOptionBool" [t| HsOption Bool |]) $(deriveMarshallableUnsafe "HsOptionBool" [t| HsOption CBool |]) $(deriveMarshallableUnsafe "HsOptionInt16" [t| HsOption CShort |]) $(deriveMarshallableUnsafe "HsOptionInt16" [t| HsOption Int16 |]) $(deriveMarshallableUnsafe "HsOptionInt32" [t| HsOption CInt |]) $(deriveMarshallableUnsafe "HsOptionInt32" [t| HsOption Int32 |]) $(deriveMarshallableUnsafe "HsOptionInt64" [t| HsOption CLong |]) $(deriveMarshallableUnsafe "HsOptionInt64" [t| HsOption Int64 |]) $(deriveMarshallableUnsafe "HsOptionUInt8" [t| HsOption CSChar |]) $(deriveMarshallableUnsafe "HsOptionUInt8" [t| HsOption Word8 |]) $(deriveMarshallableUnsafe "HsOptionUInt32" [t| HsOption CUInt |]) $(deriveMarshallableUnsafe "HsOptionUInt32" [t| HsOption Word32 |]) $(deriveMarshallableUnsafe "HsOptionUInt64" [t| HsOption CULong |]) $(deriveMarshallableUnsafe "HsOptionUInt64" [t| HsOption Word64 |]) $(deriveMarshallableUnsafe "HsOptionFloat" [t| HsOption Float |]) $(deriveMarshallableUnsafe "HsOptionFloat" [t| HsOption CFloat |]) $(deriveMarshallableUnsafe "HsOptionDouble" [t| HsOption Double |]) $(deriveMarshallableUnsafe "HsOptionDouble" [t| HsOption CDouble |]) $(deriveMarshallableUnsafe "HsOptionString" [t| HsOption HsText |]) $(deriveMarshallableUnsafe "HsOptionString" [t| HsOption HsLenientText |]) $(deriveMarshallableUnsafe "HsOptionString" [t| HsOption HsByteString |]) $(deriveMarshallableUnsafe "HsOptionStringView" [t| HsOption HsStringPiece |]) $(deriveMarshallableUnsafe "HsOptionHsJSON" [t| HsOption HsJSON |]) $(deriveMarshallableUnsafe "HsArrayInt16" [t| HsList CShort |]) $(deriveMarshallableUnsafe "HsArrayInt16" [t| HsList Int16 |]) $(deriveMarshallableUnsafe "HsArrayInt32" [t| HsList CInt |]) $(deriveMarshallableUnsafe "HsArrayInt32" [t| HsList Int32 |]) $(deriveMarshallableUnsafe "HsArrayInt64" [t| HsList Int |]) $(deriveMarshallableUnsafe "HsArrayInt64" [t| HsList Int64 |]) $(deriveMarshallableUnsafe "HsArrayInt64" [t| HsList CLong |]) $(deriveMarshallableUnsafe "HsArrayUInt8" [t| HsList CBool |]) $(deriveMarshallableUnsafe "HsArrayUInt8" [t| HsList Word8 |]) $(deriveMarshallableUnsafe "HsArrayUInt32" [t| HsList CUInt |]) $(deriveMarshallableUnsafe "HsArrayUInt32" [t| HsList Word32 |]) $(deriveMarshallableUnsafe "HsArrayUInt64" [t| HsList CULong |]) $(deriveMarshallableUnsafe "HsArrayUInt64" [t| HsList Word64 |]) $(deriveMarshallableUnsafe "HsArrayFloat" [t| HsList Float |]) $(deriveMarshallableUnsafe "HsArrayFloat" [t| HsList CFloat |]) $(deriveMarshallableUnsafe "HsArrayDouble" [t| HsList Double |]) $(deriveMarshallableUnsafe "HsArrayDouble" [t| HsList CDouble |]) $(deriveMarshallableUnsafe "HsArrayString" [t| HsList HsByteString |]) $(deriveMarshallableUnsafe "HsArrayString" [t| HsList HsText |]) $(deriveMarshallableUnsafe "HsArrayString" [t| HsList HsLenientText |]) $(deriveMarshallableUnsafe "HsArrayStringPiece" [t| HsList HsStringPiece |]) $(deriveMarshallableUnsafe "HsArrayJSON" [t| HsList HsJSON |]) $(deriveMarshallableUnsafe "HsArrayInt16" [t| HsArray CShort |]) $(deriveMarshallableUnsafe "HsArrayInt16" [t| HsArray Int16 |]) $(deriveMarshallableUnsafe "HsArrayInt32" [t| HsArray CInt |]) $(deriveMarshallableUnsafe "HsArrayInt32" [t| HsArray Int32 |]) $(deriveMarshallableUnsafe "HsArrayInt64" [t| HsArray Int |]) $(deriveMarshallableUnsafe "HsArrayInt64" [t| HsArray Int64 |]) $(deriveMarshallableUnsafe "HsArrayInt64" [t| HsArray CLong |]) $(deriveMarshallableUnsafe "HsArrayUInt8" [t| HsArray CBool |]) $(deriveMarshallableUnsafe "HsArrayUInt8" [t| HsArray Word8 |]) $(deriveMarshallableUnsafe "HsArrayUInt8" [t| HsArray CSChar |]) $(deriveMarshallableUnsafe "HsArrayUInt8" [t| HsArray CUChar |]) $(deriveMarshallableUnsafe "HsArrayUInt16" [t| HsArray CUShort |]) $(deriveMarshallableUnsafe "HsArrayUInt32" [t| HsArray CUInt |]) $(deriveMarshallableUnsafe "HsArrayUInt32" [t| HsArray Word32 |]) $(deriveMarshallableUnsafe "HsArrayUInt64" [t| HsArray CULong |]) $(deriveMarshallableUnsafe "HsArrayUInt64" [t| HsArray Word64 |]) $(deriveMarshallableUnsafe "HsArrayFloat" [t| HsArray Float |]) $(deriveMarshallableUnsafe "HsArrayFloat" [t| HsArray CFloat |]) $(deriveMarshallableUnsafe "HsArrayDouble" [t| HsArray Double |]) $(deriveMarshallableUnsafe "HsArrayDouble" [t| HsArray CDouble |]) $(deriveMarshallableUnsafe "HsArrayString" [t| HsArray HsByteString |]) $(deriveMarshallableUnsafe "HsArrayString" [t| HsArray HsText |]) $(deriveMarshallableUnsafe "HsArrayString" [t| HsArray HsLenientText |]) $(deriveMarshallableUnsafe "HsArrayStringPiece" [t| HsArray HsStringPiece |]) $(deriveMarshallableUnsafe "HsArrayJSON" [t| HsArray HsJSON |]) $(deriveMarshallableUnsafe "HsSetUInt8" [t| HsHashSet CUChar |]) $(deriveMarshallableUnsafe "HsSetUInt16" [t| HsHashSet CUShort |]) $(deriveMarshallableUnsafe "HsSetInt32" [t| HsHashSet CInt |]) $(deriveMarshallableUnsafe "HsSetInt32" [t| HsHashSet Int32 |]) $(deriveMarshallableUnsafe "HsSetInt64" [t| HsHashSet Int |]) $(deriveMarshallableUnsafe "HsSetInt64" [t| HsHashSet Int64 |]) $(deriveMarshallableUnsafe "HsSetInt64" [t| HsHashSet CLong |]) $(deriveMarshallableUnsafe "HsSetUInt8" [t| HsHashSet CBool |]) $(deriveMarshallableUnsafe "HsSetUInt8" [t| HsHashSet Word8 |]) $(deriveMarshallableUnsafe "HsSetUInt8" [t| HsHashSet CSChar |]) $(deriveMarshallableUnsafe "HsSetUInt32" [t| HsHashSet CUInt |]) $(deriveMarshallableUnsafe "HsSetUInt32" [t| HsHashSet Word32 |]) $(deriveMarshallableUnsafe "HsSetUInt64" [t| HsHashSet CULong |]) $(deriveMarshallableUnsafe "HsSetUInt64" [t| HsHashSet Word64 |]) $(deriveMarshallableUnsafe "HsSetFloat" [t| HsHashSet Float |]) $(deriveMarshallableUnsafe "HsSetDouble" [t| HsHashSet Double |]) $(deriveMarshallableUnsafe "HsSetString" [t| HsHashSet HsByteString |]) $(deriveMarshallableUnsafe "HsSetString" [t| HsHashSet HsText |]) $(deriveMarshallableUnsafe "HsSetString" [t| HsHashSet HsLenientText |]) $(deriveMarshallableUnsafe "HsSetJSON" [t| HsHashSet HsJSON |]) $(deriveMarshallableUnsafe "HsMapIntInt" [t| HsIntMap Int |]) $(deriveMarshallableUnsafe "HsMapUInt8UInt8" [t| HsHashMap CUChar CUChar |]) $(deriveMarshallableUnsafe "HsMapUInt16UInt16" [t| HsHashMap CUShort CUShort |]) $(deriveMarshallableUnsafe "HsMapIntDouble" [t| HsIntMap Double |]) $(deriveMarshallableUnsafe "HsMapIntString" [t| HsIntMap HsByteString |]) $(deriveMarshallableUnsafe "HsMapIntString" [t| HsIntMap HsText |]) $(deriveMarshallableUnsafe "HsMapIntString" [t| HsIntMap HsLenientText |]) $(deriveMarshallableUnsafe "HsMapStringInt" [t| HsObject Int |]) $(deriveMarshallableUnsafe "HsMapStringDouble" [t| HsObject Double |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsObject HsByteString |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsObject HsText |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsObject HsLenientText |]) $(deriveMarshallableUnsafe "HsMapIntInt" [t| HsHashMap Int Int |]) $(deriveMarshallableUnsafe "HsMapInt32Int32" [t| HsHashMap Int32 Int32 |]) $(deriveMarshallableUnsafe "HsMapInt32Double" [t| HsHashMap Int32 Double |]) $(deriveMarshallableUnsafe "HsMapInt32String" [t| HsHashMap Int32 HsText |]) $(deriveMarshallableUnsafe "HsMapInt32String" [t| HsHashMap Int32 HsLenientText |]) $(deriveMarshallableUnsafe "HsMapInt32String" [t| HsHashMap Int32 HsByteString |]) $(deriveMarshallableUnsafe "HsMapDoubleInt32" [t| HsHashMap Double Int32 |]) $(deriveMarshallableUnsafe "HsMapStringInt32" [t| HsHashMap HsByteString Int32 |]) $(deriveMarshallableUnsafe "HsMapStringInt32" [t| HsHashMap HsText Int32 |]) $(deriveMarshallableUnsafe "HsMapStringInt32" [t| HsHashMap HsLenientText Int32 |]) $(deriveMarshallableUnsafe "HsMapStringDouble" [t| HsHashMap HsByteString Double |]) $(deriveMarshallableUnsafe "HsMapStringDouble" [t| HsHashMap HsText Double |]) $(deriveMarshallableUnsafe "HsMapStringDouble" [t| HsHashMap HsLenientText Double |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsText HsText |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsText HsByteString |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsLenientText HsLenientText |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsLenientText HsByteString |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsByteString HsText |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsByteString HsLenientText |]) $(deriveMarshallableUnsafe "HsMapStringString" [t| HsHashMap HsByteString HsByteString |]) $(deriveMarshallableUnsafe "HsObjectJSON" [t| HsObject HsJSON |]) $(deriveMarshallableUnsafe "HsJSON" [t| HsJSON |]) -- These are mutually recurisve, we have to splice them together $(do a <- deriveHsArrayUnsafe "HsJSON" [t| HsJSON |] b <- deriveHsArrayUnsafe "String" [t| HsText |] c <- [d| instance Constructible HsJSON where newValue (HsJSON _val) = error $ "HsStruct.HsJSON cannot be built on heap" constructValue ptr (HsJSON val) = case val of Null -> c_constructHsJSONNull ptr Bool b -> c_constructHsJSONBool ptr (fromBool b) Number n -> case (floatingOrInteger n :: Either CDouble CLong) of Left r -> c_constructHsJSONDouble ptr r Right _ -> case toBoundedInteger n of Just i -> c_constructHsJSONInt ptr i Nothing -> c_constructHsJSONDouble ptr $ toRealFloat n String txt -> withCxxObject (HsText txt) $ c_constructHsJSONString ptr Array v -> withCxxObject (HsArray (Vector.map HsJSON v)) $ c_constructHsJSONArray ptr Object o -> withCxxObject (HsObject (HsJSON <$> o)) $ c_constructHsJSONObject ptr instance Constructible (HsObject HsJSON) where newValue (HsObject _o) = error "HsObject HsJSON cannot be made on heap" constructValue ptr (HsObject m) = withCxxObject (HsArray (Vector.fromList (map (HsText . keyToText) keys))) $ \keys_p -> withCxxObject (HsArray (Vector.fromList vals)) $ \vals_p -> c_constructHsObjectJSON ptr keys_p vals_p where (keys, vals) = unzip $ objectToList m |] return $ a ++ b ++ c ) -- Derive constructions after marshallable $(#{derive_hs_option_unsafe Bool} [t| Bool |]) $(#{derive_hs_option_unsafe Bool} [t| CBool |]) $(#{derive_hs_option_unsafe Int16} [t| CShort |]) $(#{derive_hs_option_unsafe Int16} [t| Int16 |]) $(#{derive_hs_option_unsafe Int32} [t| CInt |]) $(#{derive_hs_option_unsafe Int32} [t| Int32 |]) $(#{derive_hs_option_unsafe Int64} [t| CLong |]) $(#{derive_hs_option_unsafe Int64} [t| Int64 |]) $(#{derive_hs_option_unsafe UInt8} [t| CSChar |]) $(#{derive_hs_option_unsafe UInt8} [t| Word8 |]) $(#{derive_hs_option_unsafe UInt32} [t| CUInt |]) $(#{derive_hs_option_unsafe UInt32} [t| Word32 |]) $(#{derive_hs_option_unsafe UInt64} [t| CULong |]) $(#{derive_hs_option_unsafe UInt64} [t| Word64 |]) $(#{derive_hs_option_unsafe Float} [t| Float |]) $(#{derive_hs_option_unsafe Float} [t| CFloat |]) $(#{derive_hs_option_unsafe Double} [t| Double |]) $(#{derive_hs_option_unsafe Double} [t| CDouble |]) $(#{derive_hs_option_unsafe String} [t| HsText |]) $(#{derive_hs_option_unsafe String} [t| HsLenientText |]) $(#{derive_hs_option_unsafe String} [t| HsByteString |]) $(#{derive_hs_option_unsafe StringView} [t| HsStringPiece |]) $(#{derive_hs_option_unsafe HsJSON} [t| HsJSON |]) $(deriveHsArrayUnsafe "Int16" [t| CShort |]) $(deriveHsArrayUnsafe "Int16" [t| Int16 |]) $(deriveHsArrayUnsafe "Int32" [t| CInt |]) $(deriveHsArrayUnsafe "Int32" [t| Int32 |]) $(deriveHsArrayUnsafe "Int64" [t| CLong |]) $(deriveHsArrayUnsafe "Int64" [t| Int64 |]) $(deriveHsArrayUnsafe "UInt8" [t| CBool |]) $(deriveHsArrayUnsafe "UInt8" [t| Word8 |]) $(deriveHsArrayUnsafe "UInt8" [t| CUChar |]) $(deriveHsArrayUnsafe "UInt8" [t| CSChar |]) $(deriveHsArrayUnsafe "UInt16" [t| CUShort |]) $(deriveHsArrayUnsafe "UInt32" [t| CUInt |]) $(deriveHsArrayUnsafe "UInt32" [t| Word32 |]) $(deriveHsArrayUnsafe "UInt64" [t| CULong |]) $(deriveHsArrayUnsafe "UInt64" [t| Word64 |]) $(deriveHsArrayUnsafe "Float" [t| Float |]) $(deriveHsArrayUnsafe "Float" [t| CFloat |]) $(deriveHsArrayUnsafe "Double" [t| Double |]) $(deriveHsArrayUnsafe "Double" [t| CDouble |]) $(deriveHsArrayUnsafe "String" [t| HsLenientText |]) $(deriveHsArrayUnsafe "String" [t| HsByteString |]) $(deriveHsArrayUnsafe "StringView" [t| HsStringPiece |]) $(deriveHsHashSetUnsafe "Int16" [t| CShort |]) $(deriveHsHashSetUnsafe "Int16" [t| Int16 |]) $(deriveHsHashSetUnsafe "Int32" [t| CInt |]) $(deriveHsHashSetUnsafe "Int32" [t| Int32 |]) $(deriveHsHashSetUnsafe "Int64" [t| Int |]) $(deriveHsHashSetUnsafe "Int64" [t| Int64 |]) $(deriveHsHashSetUnsafe "Int64" [t| CLong |]) $(deriveHsHashSetUnsafe "UInt8" [t| CBool |]) $(deriveHsHashSetUnsafe "UInt8" [t| Word8 |]) $(deriveHsHashSetUnsafe "UInt8" [t| CSChar |]) $(deriveHsHashSetUnsafe "UInt8" [t| CUChar |]) $(deriveHsHashSetUnsafe "UInt16" [t| CUShort |]) $(deriveHsHashSetUnsafe "UInt32" [t| CUInt |]) $(deriveHsHashSetUnsafe "UInt32" [t| Word32 |]) $(deriveHsHashSetUnsafe "UInt64" [t| CULong |]) $(deriveHsHashSetUnsafe "UInt64" [t| Word64 |]) $(deriveHsHashSetUnsafe "Float" [t| Float |]) $(deriveHsHashSetUnsafe "Double" [t| Double |]) $(deriveHsHashSetUnsafe "String" [t| HsByteString |]) $(deriveHsHashSetUnsafe "String" [t| HsText |]) $(deriveHsHashSetUnsafe "String" [t| HsLenientText |]) $(deriveHsHashSetUnsafe "HsJSON" [t| HsJSON |]) -- O(n^2) derivations, try to derive just what you need $(deriveHsHashMapUnsafe "IntInt" [t| Int |] [t| Int |]) $(deriveHsHashMapUnsafe "UInt8UInt8" [t| CUChar |] [t| CUChar |]) $(deriveHsHashMapUnsafe "UInt16UInt16" [t| CUShort |] [t| CUShort |]) $(deriveHsHashMapUnsafe "Int32Int32" [t| Int32 |] [t| Int32 |]) $(deriveHsHashMapUnsafe "Int32Double" [t| Int32 |] [t| Double |]) $(deriveHsHashMapUnsafe "Int32String" [t| Int32 |] [t| HsByteString |]) $(deriveHsHashMapUnsafe "Int32String" [t| Int32 |] [t| HsText |]) $(deriveHsHashMapUnsafe "Int32String" [t| Int32 |] [t| HsLenientText |]) $(deriveHsHashMapUnsafe "DoubleInt32" [t| Double |] [t| Int32 |]) $(deriveHsHashMapUnsafe "StringInt32" [t| HsByteString |] [t| Int32 |]) $(deriveHsHashMapUnsafe "StringInt32" [t| HsText |] [t| Int32 |]) $(deriveHsHashMapUnsafe "StringInt32" [t| HsLenientText |] [t| Int32 |]) $(deriveHsHashMapUnsafe "StringDouble" [t| HsText |] [t| Double |]) $(deriveHsHashMapUnsafe "StringDouble" [t| HsLenientText |] [t| Double |]) $(deriveHsHashMapUnsafe "StringDouble" [t| HsByteString |] [t| Double |]) $(deriveHsHashMapUnsafe "StringString" [t| HsText |] [t| HsText |]) $(deriveHsHashMapUnsafe "StringString" [t| HsText |] [t| HsByteString |]) $(deriveHsHashMapUnsafe "StringString" [t| HsLenientText |] [t| HsLenientText |]) $(deriveHsHashMapUnsafe "StringString" [t| HsLenientText |] [t| HsByteString |]) $(deriveHsHashMapUnsafe "StringString" [t| HsByteString |] [t| HsText |]) $(deriveHsHashMapUnsafe "StringString" [t| HsByteString |] [t| HsLenientText |]) $(deriveHsHashMapUnsafe "StringString" [t| HsByteString |] [t| HsByteString |])