packages feed

hoppy-docs 0.2.1 → 0.3.0

raw patch · 2 files changed

+114/−16 lines, 2 filesdep ~hoppy-generatordep ~hoppy-runtimePVP ok

version bump matches the API change (PVP)

Dependency ranges changed: hoppy-generator, hoppy-runtime

API changes (from Hackage documentation)

Files

hoppy-docs.cabal view
@@ -1,5 +1,5 @@ name: hoppy-docs-version: 0.2.1+version: 0.3.0 synopsis: C++ FFI generator - Documentation homepage: http://khumba.net/projects/hoppy license: AGPL-3@@ -21,8 +21,8 @@   build-depends:       base >=4.7 && <5     , haskell-src >=1.0 && <1.1-    , hoppy-generator >=0.2 && <0.3-    , hoppy-runtime >=0.2 && <0.3+    , hoppy-generator >=0.3 && <0.4+    , hoppy-runtime >=0.3 && <0.4   hs-source-dirs: src   ghc-options: -W -fwarn-incomplete-patterns -fwarn-unused-do-bind   default-language: Haskell2010
src/Foreign/Hoppy/Documentation/UsersGuide.hs view
@@ -75,6 +75,9 @@    -- *** Object passing   -- $generators-hs-object-passing++  -- *** Exceptions+  -- $generators-hs-exceptions   ) where  import Data.Bits (Bits)@@ -85,7 +88,7 @@ import Foreign.Hoppy.Generator.Types import Foreign.Hoppy.Generator.Version import Foreign.Hoppy.Runtime-import Foreign.Ptr (Ptr)+import Foreign.Ptr (FunPtr, Ptr) import Language.Haskell.Syntax (HsType) import System.IO.Unsafe (unsafePerformIO) @@ -190,6 +193,11 @@ types are converted to equivalent types on both ends, and pointer types in C++ are represented by corresponding pointer types in Haskell. +For numbers, Haskell declares a number of numeric types in "Foreign.C" for+interfacing with C directly.  Hoppy maps C++ numbers to these types, with the+exception of `bool`, `int`, `float`, and `double`, which map to their native+Haskell equivalents instead ('Bool', 'Int', 'Float', 'Double').+ Raw object types (not pointers or references, just the by-value object types, i.e. 'objT') are treated differently.  When an object is taken or returned by value, this typically indicates a lightweight object that is easy to copy, so@@ -198,6 +206,11 @@ having objects be handed off to a foreign garbage collector.  See 'ClassConversion' for more on object conversions. +Internally, only C types are exchanged over the gateway, since these are what is+common to both languages.  Conversions are performed on both sides of the+gateway.  In most cases, the C++, C, and Haskell types all have equivalent+representation no conversion is necessary.+ -} {- $generators @@ -225,7 +238,9 @@  Cycles between generated C++ modules are not supported.  This can currently only happen because of @#include@ cycles involving callbacks, since callbacks are the-only 'Export's that can be referenced by other generated C++ code.+only 'Export's that can be referenced by other generated C++ code.  Also, C+++callbacks that handle exceptions depend on the interface's exception support+module (see 'interfaceExceptionSupportModule').  -} {- $generators-cpp-object-passing@@ -300,16 +315,27 @@ > > callbackT :: Callback -> Type -We want to call some foreign code from C++.  What C++ type do we associate with-such an entry point?  (Both the C++ and foreign sides of the callback will need-to perform en-\/decoding of arguments\/return values.)+We want to call some foreign code from C++.  There are two choices for doing so,+described below.  Declaring a callback provides support for both types of+invocation. -__Function pointer:__ Create a function pointer to a foreign wrapper which does-en-/decoding on the foreign side.  But then we need to wrap this in a C++-function (pointer) which does the C++-side conversions.  Function pointers can't-close over variables, so this doesn't work.+__Function pointer:__ Function pointers are expressed with a @'ptrT' ('fnT'+...)@ type.  Foreign runtimes' FFIs can provide a means for creating raw+function pointers directly (Haskell's does with 'FunPtr').  Hoppy provides an+optional layer that performs the necessary type conversions, but only the+foreign half of the conversions, so only C types can be used within function+pointer types (this is a limitation of speaking over a C FFI; an error is+signaled when trying to use a type that requires C\<-\>C++ conversion).  The+other downside of using function pointers is that C++ provides no lifetime+tracking, and because in general foreign code can't know how long some C++ code+is going to hold a function pointer, it's necessary to manage the lifetime of+the pointer manually. -__C++ functor:__ Create a class G that takes a foreign function pointer and+__C++ functor:__ This is the preferred method for calling into foreign code.+This type is expressed with 'callbackT'.  It wraps the function pointer support+above in C++ functors that add automatic lifetime tracking.++Internally, we create a class G that takes a foreign function pointer and implements @operator()@, performing the necessary conversions around invoking the pointer.  In the event that the function pointer is dynamically allocated (as in Haskell), then this class also ties the lifetime of the function pointer@@ -457,10 +483,40 @@ -} {- $generators-hs-module-structure-callbacks -Despite needing to be exported as with other 'Export' choices, 'Callback's do-not expose anything to the user.  Instead, they provide machinery for functions-to be able to use 'callbackT'.+Declared callbacks provide support for callback types ('callbackT') as well as+function pointers (@'ptrT' ('fnT' ...)@) in Haskell. +Callback types manifest directly as Haskell function types in @IO@.  Function+pointers manifest as 'FunPtr's around Haskell function types in @IO@.++No runtime support is exposed to the user for working with callback types+(internal machinery is generated however).  For function pointer types, a+function `callbackName_newFunPtr` is exposed from the callback's module that+makes it easy to wrap anonymous functions in 'FunPtr's that perform the Haskell+side of conversions, with code like the following:++> -- Generator bindings+>+> cb_intCallback = makeCallback "IntCallback" [intT] intT+>+> f_funPtrTest = makeFn "funPtrTest" Nothing Nonpure [ptrT $ fnT [intT] intT] intT+>+> f_callbackTest = makeFn "callbackTest" Nothing Nonpure [callbackT cb_intCallback] intT++> -- Test program+>+> import Foreign.C (CInt)+> import Foreign.Hoppy.Runtime (withScopedFunPtr)+>+> -- Generated things:+> intCallback_newFunPtr :: (Int -> IO Int) -> IO (FunPtr (CInt -> IO CInt))+> funPtrTest :: FunPtr (CInt -> IO CInt) -> Int+> callbackTest :: (Int -> IO Int) -> Int+>+> -- Driver code:+> callFunPtrTest = withScopedFunPtr (intCallback_newFunPtr $ return . (* 2)) funPtrTest+> callCallbackTest = callbackTest $ return . (* 2)+ -} {- $generators-hs-module-structure-classes @@ -634,5 +690,47 @@ managed pointers would balloon the size of bindings.  Unmanaged objects can be converted to managed objects with 'toGc'; after calling this function, the value it returns should always be used in place of any existing pointers.++-}+{- $generators-hs-exceptions++C++ exceptions can caught and thrown in Haskell.  C++ entities that deal with+exceptions need to be marked as such, for Hoppy to generate the support code for+them.  To work with exceptions at all, you need to pick one of your Hoppy+modules to contain some runtime support code, using+'interfaceSetExceptionSupportModule'.  C++ functions that throw need to be+marked with the specific exceptions that they throw, using 'handleExceptions'.+Callbacks that want to be able to throw need to be marked with+'callbackSetThrows', after which they are allowed to throw any exception classes+defined in the interface.  Exception handling in both directions can also be set+up at the module and interface levels using 'handleExceptions',+'interfaceSetCallbacksThrow', and 'moduleSetCallbacksThrow'.++Classes can be marked as being exception classes with 'classMakeException'.+Exception classes need to be copyable, so make sure to define a copy constructor+(use 'Copyable').++C++ exceptions in Haskell are handled with 'throwCpp' and 'catchCpp'.  While+they use Haskell exceptions under the hood, do not use 'throw' and 'catch' to+work with them; this may leak C++ objects.++Catching a wildcard (i.e. @catch (...)@) is supported, but no information is+available about the caught value.++Implementation-wise, an in-flight C++ exception in Haskell always owns the+object (which is on the heap).  An exception coming from C++ into Haskell (it's+a heap temporary) will be given to the garbage collector.  Hence, for ease of+use, caught exceptions should always be garbage-collected.  Also, when throwing+from Haskell, throwing will always take ownership of the object.  If 'throwCpp'+gets a non-GCed object, then it will be given to the garbage collector; and then+the exception will be thrown as a Haskell exception.  If the exception+propagates out to a callback and back into C++, then a temporary non-GCed copy+will be passed over the gateway, and rethrown as a value object on the C++ side.++In the above strategy, when throwing an exception from Haskell that propagates+to C++, it is wasteful to make the thrown object GCed, just to have to create a+non-GCed copy.  So when we throw from Haskell, we don't actually assign to the+garbage collector immediately (if it's not already); instead, we delay the+'toGc' call until 'catchCpp'.  -}