packages feed

marshal-contt 0.1.2.1 → 0.2.0.0

raw patch · 4 files changed

+397/−7 lines, 4 filesdep +kan-extensionsdep ~bytestringdep ~lensPVP ok

version bump matches the API change (PVP)

Dependencies added: kan-extensions

Dependency ranges changed: bytestring, lens

API changes (from Hackage documentation)

+ Foreign.Marshal.Codensity: Codensity :: (forall (b :: k). () => (a -> m b) -> m b) -> Codensity a
+ Foreign.Marshal.Codensity: [runCodensity] :: Codensity a -> forall (b :: k). () => (a -> m b) -> m b
+ Foreign.Marshal.Codensity: alloca :: Storable a => Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArray :: Storable a => Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArray0 :: Storable a => Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArrayWith :: (Foldable f, Storable a) => f a -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArrayWith' :: (Foldable f, Storable b) => (a -> Codensity IO b) -> f a -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: allocaArrayWith0 :: (Foldable f, Storable a) => f a -> a -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArrayWith0' :: (Foldable f, Storable b) => (a -> Codensity IO b) -> f a -> b -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: allocaArrayWith0Of :: Storable a => Fold s a -> s -> a -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArrayWith0Of' :: Storable b => Fold s a -> (a -> Codensity IO b) -> s -> b -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: allocaArrayWithOf :: Storable a => Fold s a -> s -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaArrayWithOf' :: Storable b => Fold s a -> (a -> Codensity IO b) -> s -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: allocaBytes :: Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaBytesAligned :: Int -> Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: allocaWith :: Storable a => a -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: bracketCodensity :: (a -> IO b) -> (a -> IO c) -> Codensity IO a -> Codensity IO a
+ Foreign.Marshal.Codensity: calloc :: forall a. Storable a => Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: callocArray :: forall a. Storable a => Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: callocArray0 :: forall a. Storable a => Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: callocBytes :: Int -> Codensity IO (Ptr a)
+ Foreign.Marshal.Codensity: class ToCString a
+ Foreign.Marshal.Codensity: data Ptr a
+ Foreign.Marshal.Codensity: iallocaArrayWith' :: (FoldableWithIndex i f, Storable b) => (i -> a -> Codensity IO b) -> f a -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: iallocaArrayWith0' :: (FoldableWithIndex i f, Storable b) => (i -> a -> Codensity IO b) -> f a -> b -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: iallocaArrayWith0Of' :: Storable b => AnIndexedFold i s a -> (i -> a -> Codensity IO b) -> s -> b -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: iallocaArrayWithOf' :: Storable b => AnIndexedFold i s a -> (i -> a -> Codensity IO b) -> s -> Codensity IO (Ptr b)
+ Foreign.Marshal.Codensity: instance Foreign.Marshal.Codensity.ToCString Data.ByteString.Internal.ByteString
+ Foreign.Marshal.Codensity: instance Foreign.Marshal.Codensity.ToCString Data.ByteString.Short.Internal.ShortByteString
+ Foreign.Marshal.Codensity: instance Foreign.Marshal.Codensity.ToCString GHC.Base.String
+ Foreign.Marshal.Codensity: lowerCodensity :: Applicative f => Codensity f a -> f a
+ Foreign.Marshal.Codensity: newtype Codensity (m :: k -> TYPE rep) a :: forall k (rep :: RuntimeRep). () => k -> TYPE rep -> Type -> Type
+ Foreign.Marshal.Codensity: nullPtr :: () => Ptr a
+ Foreign.Marshal.Codensity: type CString = Ptr CChar
+ Foreign.Marshal.Codensity: type CStringLen = (Ptr CChar, Int)
+ Foreign.Marshal.Codensity: type AnIndexedFold i s a = forall m p. (Indexable i p) => p a (Const m a) -> s -> Const m s
+ Foreign.Marshal.Codensity: withCString :: ToCString a => a -> Codensity IO CString
+ Foreign.Marshal.Codensity: withCStringLen :: ToCString a => a -> Codensity IO CStringLen
+ Foreign.Marshal.Codensity: withForeignPtr :: ForeignPtr a -> Codensity IO (Ptr a)
+ Foreign.Marshal.ContT: ContT :: ((a -> m r) -> m r) -> ContT a
+ Foreign.Marshal.ContT: [runContT] :: ContT a -> (a -> m r) -> m r
+ Foreign.Marshal.ContT: lowerContT :: Monad m => ContT a m a -> m a
+ Foreign.Marshal.ContT: newtype ContT (r :: k) (m :: k -> Type) a :: forall k. () => k -> k -> Type -> Type -> Type

Files

CHANGELOG.md view
@@ -1,5 +1,10 @@ # Revision history for marshal-contt +## 0.2.0.0 -- 2019-09-15++* Add new `Foreign.Marshal.Codensity` module to expose an equivalent interface+  in terms of a different monadic abstraction for continuation-based code.+ ## 0.1.2.1 -- 2019-09-14  * Fix documentation bugs.
marshal-contt.cabal view
@@ -1,5 +1,5 @@ name:                marshal-contt-version:             0.1.2.1+version:             0.2.0.0 synopsis:            A ContT-based wrapper for Haskell-to-C marshalling functions. description:         See <https://github.com/typedrat/marshal-contt/blob/master/README.md>. homepage:            https://github.com/typedrat/marshal-contt@@ -16,10 +16,12 @@  library   exposed-modules:     Foreign.Marshal.ContT-  build-depends:       base        >= 4.9       && < 5-                     , mtl         >= 2.2       && < 2.3-                     , bytestring  >= 0.10.10.0 && < 0.11-                     , lens        >= 4.16      && < 4.19+                     , Foreign.Marshal.Codensity+  build-depends:       base           >= 4.9       && < 5+                     , mtl            >= 2.2       && < 2.3+                     , bytestring     >= 0.10.10.0 && < 0.11+                     , kan-extensions >= 5.2       && < 5.3+                     , lens           >= 4.16      && < 4.19   hs-source-dirs:      src   default-language:    Haskell2010   default-extensions:  FlexibleInstances
+ src/Foreign/Marshal/Codensity.hs view
@@ -0,0 +1,375 @@+{-|+Module      : Foreign.Marshal.Codensity+Description : A Codensity-based wrapper for Haskell-to-C marshalling functions.+Copyright   : (c) Alexis Williams, 2019+License     : MPL-2.0+Maintainer  : alexis@typedr.at+Stability   : provisional+Portability : portable++This library wraps the standard @base@ bracketed allocation primitives (along+with those from "Data.ByteString" and "Data.ByteString.Short") in a+'Codensity'-based interface to ease the chaining of complex marshalling+operations.+-}+module Foreign.Marshal.Codensity+    (+    -- * @alloca@+      alloca, allocaWith, allocaBytes, allocaBytesAligned+    -- * @calloc@+    , calloc, callocBytes+    -- * @allocaArray@+    , allocaArray, allocaArrayWith, allocaArrayWithOf+    , allocaArray0, allocaArrayWith0, allocaArrayWith0Of+    -- * @callocArray@+    , callocArray, callocArray0+    -- * @withForeignPtr@ (and alternatives)+    , withForeignPtr+    , bracketCodensity+    -- * @ToCString@+    , ToCString(..)+    -- * Reexports+    , CString, CStringLen+    , Ptr, nullPtr+    , Codensity(..)+    , lowerCodensity+    -- * Projected variants+    -- | These variants work in the same way as their corresponding functions+    --   without the terminal prime, but with a function argument that projects+    --   the results of the (possibly implicit) 'Fold' into a 'Storable' value.+    --+    --   As in the @lens@ library, the variants beginning with an @i@ use+    --   'IndexedFold's rather than 'Fold's, and no versions without terminal+    --   primes exist because there is no generic enough use for indexes to+    --   give a sensible default.+    , AnIndexedFold+    , allocaArrayWith', allocaArrayWithOf'+    , iallocaArrayWith', iallocaArrayWithOf'+    , allocaArrayWith0', allocaArrayWith0Of'+    , iallocaArrayWith0', iallocaArrayWith0Of'+    ) where++import           Control.Exception     ( finally )+import           Control.Lens.Fold+import           Control.Lens.Getter+import           Control.Lens.Indexed+-- For documentation:+import           Control.Lens.Type     ( IndexedTraversal, IndexedLens )+import           Control.Monad.Codensity+import           Control.Monad.IO.Class+import qualified Data.ByteString       as BS+import qualified Data.ByteString.Short as SBS+import           Data.Foldable         ( foldrM )+import           Data.Functor          ( ($>) )+import qualified Foreign.C.String      as C+import           Foreign.C.String      ( CString, CStringLen )+import qualified Foreign.ForeignPtr    as C+import           Foreign.ForeignPtr    ( ForeignPtr )+import qualified Foreign.Marshal.Alloc as C+import qualified Foreign.Marshal.Array as C+import           Foreign.Marshal.Utils ( fillBytes )+import           Foreign.Ptr+import           Foreign.Storable++-- | 'alloca' @\@a@ is a continuation that provides access to a pointer into a+--   temporary block of memory sufficient to hold values of type @a@.+alloca :: Storable a => Codensity IO (Ptr a)+alloca = Codensity C.alloca+{-# INLINE alloca #-}++-- | 'allocaWith' @a@ is a continuation that provides access to a pointer into+--   a temporary block of memory containing @a@.+allocaWith :: Storable a => a -> Codensity IO (Ptr a)+allocaWith val = do+    ptr <- alloca+    liftIO $ poke ptr val+    return ptr+{-# INLINE allocaWith #-}++-- | 'allocaBytes' @n@ is a continuation that provides access to a pointer into+--   a temporary block of memory sufficient to hold @n@ bytes, with+--   machine-standard alignment.+allocaBytes :: Int -> Codensity IO (Ptr a)+allocaBytes size = Codensity $ C.allocaBytes size+{-# INLINE allocaBytes #-}++-- | 'allocaBytesAligned' @n@ @a@ is a continuation that provides access to a+--   pointer into a temporary block of memory sufficient to hold @n@ bytes, +--   with @a@-byte alignment.+allocaBytesAligned :: Int -> Int -> Codensity IO (Ptr a)+allocaBytesAligned size align = Codensity $ C.allocaBytesAligned size align+{-# INLINE allocaBytesAligned #-}++-- | 'bracketCodensity' allows one to add initialization and finalization hooks to+--   an existing 'Codensity' that will be executed even in cases where an exception+--   occurs.+--+--   This provides an alternative to 'ForeignPtr's when the pointer will only+--   be used in code that is written with this library in mind.+bracketCodensity :: (a -> IO b) -> (a -> IO c) -> Codensity IO a -> Codensity IO a+bracketCodensity init' final m = do+    a <- m+    liftIO $ init' a+    wrapCodensity (`finally` final a)+    return a+{-# INLINE bracketCodensity #-}++--++-- | 'calloc' @\@a@ is a continuation that provides access to a pointer into a+--   temporary block of zeroed memory sufficient to hold values of type @a@.+calloc :: forall a. Storable a => Codensity IO (Ptr a)+calloc = do+    ptr <- alloca+    let size = sizeOf (undefined :: a)+    liftIO $ fillBytes ptr 0 size+    return ptr+{-# INLINE calloc #-}++-- | 'callocBytes' @n@ is a continuation that provides access to a pointer into+--   a temporary block of zeroed memory sufficient to hold @n@ bytes, with+--   machine-standard alignment.+callocBytes :: Int -> Codensity IO (Ptr a)+callocBytes size = do+    ptr <- allocaBytes size+    liftIO $ fillBytes ptr 0 size+    return ptr+{-# INLINE callocBytes #-}++--++-- | 'allocaArray' @\@a@ @n@ is a continuation that provides access to a+--   pointer into a temporary block of memory sufficient to hold @n@ values of+--   type @a@.+allocaArray :: Storable a => Int -> Codensity IO (Ptr a)+allocaArray size = Codensity (C.allocaArray size)+{-# INLINE allocaArray #-}++-- | 'allocaArrayWith' @xs@ is a continuation that provides access to a+--   pointer into a temporary block of memory containing the values of @xs@.+allocaArrayWith :: (Foldable f, Storable a) => f a -> Codensity IO (Ptr a)+allocaArrayWith = allocaArrayWith' return+{-# INLINE allocaArrayWith #-}++-- Why isn't this defined as `allocaArrayWithOf' folded`? I don't want to+-- lose the potential performance benefits of a specialized `length`.+allocaArrayWith' :: (Foldable f, Storable b) +                 => (a -> Codensity IO b) +                 -> f a -> Codensity IO (Ptr b)+allocaArrayWith' f xs = do+    ptr <- allocaArray (length xs)+    _ <- foldrM go ptr xs+    return ptr+    where+        go x ptr = do+            x' <- f x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE allocaArrayWith' #-}++-- | 'allocaArrayWithOf' @f@ works in the same way as 'allocaArrayWith', but+--   using the 'Fold' @f@ rather than any 'Foldable' instance.+allocaArrayWithOf :: (Storable a) => Fold s a -> s -> Codensity IO (Ptr a)+allocaArrayWithOf fold = allocaArrayWithOf' fold return +{-# INLINE allocaArrayWithOf #-}++allocaArrayWithOf' :: (Storable b) +                   => Fold s a+                   -> (a -> Codensity IO b) +                   -> s -> Codensity IO (Ptr b)+allocaArrayWithOf' fold f xs = do+    ptr <- allocaArray (lengthOf fold xs)+    _ <- foldrMOf fold go ptr xs+    return ptr+    where+        go x ptr = do+            x' <- f x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE allocaArrayWithOf' #-}++iallocaArrayWith' :: (FoldableWithIndex i f, Storable b)+                  => (i -> a -> Codensity IO b)+                  -> f a -> Codensity IO (Ptr b)+iallocaArrayWith' f xs = do+    ptr <- allocaArray (length xs)+    _ <- ifoldrMOf ifolded go ptr xs+    return ptr+    where+        go i x ptr = do+            x' <- f i x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE iallocaArrayWith' #-}++-- | A generic 'IndexedFold' or equivalent, taking an 'IndexedGetter',+--   'IndexedFold' (obviously), 'Control.Lens.Type.IndexedTraversal', or+--   'Control.Lens.Type.IndexedLens'.+type AnIndexedFold i s a = forall m p. (Indexable i p)+                        => p a (Const m a) +                        -> s -> Const m s++iallocaArrayWithOf' :: (Storable b) +                    => AnIndexedFold i s a+                    -> (i -> a -> Codensity IO b)+                    -> s -> Codensity IO (Ptr b)+iallocaArrayWithOf' fold f xs = do+    ptr <- allocaArray (lengthOf fold xs)+    _ <- ifoldrMOf fold go ptr xs+    return ptr+    where+        go i x ptr = do+            x' <- f i x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE iallocaArrayWithOf' #-}++--++-- | 'allocaArray0' @\@a@ @n@ is a continuation that provides access to a+--   pointer into a temporary block of memory sufficient to hold @n@ values of+--   type @a@, along with a final terminal element.+allocaArray0 :: Storable a => Int -> Codensity IO (Ptr a)+allocaArray0 len = Codensity (C.allocaArray0 len)+{-# INLINE allocaArray0 #-}++-- | 'allocaArrayWith0' @xs@ @end@ is a continuation that provides access to a+--   pointer into a temporary block of memory containing the values of @xs@,+--   terminated with @end@.+allocaArrayWith0 :: (Foldable f, Storable a) +                 => f a -> a -> Codensity IO (Ptr a)+allocaArrayWith0 = allocaArrayWith0' return+{-# INLINE allocaArrayWith0 #-}++allocaArrayWith0' :: (Foldable f, Storable b)+                  => (a -> Codensity IO b)+                  -> f a -> b -> Codensity IO (Ptr b)+allocaArrayWith0' f xs end = do+    ptr <- allocaArray (length xs)+    endPtr <- foldrMOf folded go ptr xs+    liftIO $ poke endPtr end+    return ptr+    where+        go x ptr = do+            x' <- f x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE allocaArrayWith0' #-}++-- | 'allocaArrayWith0Of' @t@ works in the same way as 'allocaArrayWith0', but+--   using the 'Fold' @t@ rather than any 'Foldable' instance.+allocaArrayWith0Of :: (Storable a) => Fold s a -> s -> a -> Codensity IO (Ptr a)+allocaArrayWith0Of fold = allocaArrayWith0Of' fold return +{-# INLINE allocaArrayWith0Of #-}++allocaArrayWith0Of' :: (Storable b) +                    => Fold s a+                    -> (a -> Codensity IO b) +                    -> s -> b -> Codensity IO (Ptr b)+allocaArrayWith0Of' fold f xs end = do+    ptr <- allocaArray (lengthOf fold xs)+    endPtr <- foldrMOf fold go ptr xs+    liftIO $ poke endPtr end+    return ptr+    where+        go x ptr = do+            x' <- f x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE allocaArrayWith0Of' #-}++iallocaArrayWith0' :: (FoldableWithIndex i f, Storable b)+                   => (i -> a -> Codensity IO b)+                   -> f a -> b -> Codensity IO (Ptr b)+iallocaArrayWith0' f xs end = do+    ptr <- allocaArray (length xs)+    endPtr <- ifoldrMOf ifolded go ptr xs+    liftIO $ poke endPtr end+    return ptr+    where+        go i x ptr = do+            x' <- f i x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE iallocaArrayWith0' #-}++iallocaArrayWith0Of' :: (Storable b)+                     => AnIndexedFold i s a+                     -> (i -> a -> Codensity IO b)+                     -> s -> b -> Codensity IO (Ptr b)+iallocaArrayWith0Of' fold f xs end = do+    ptr <- allocaArray (lengthOf fold xs)+    endPtr <- ifoldrMOf fold go ptr xs+    liftIO $ poke endPtr end+    return ptr+    where+        go i x ptr = do+            x' <- f i x+            liftIO $ poke ptr x'+            return (C.advancePtr ptr 1)+{-# INLINE iallocaArrayWith0Of' #-}++--++-- | 'callocArray' @\@a@ @n@ is a continuation that provides access to a+--   pointer into a temporary block of zeroed memory sufficient to hold @n@+--   values of type @a@.+callocArray :: forall a . Storable a => Int -> Codensity IO (Ptr a)+callocArray len = do+    ptr <- allocaArray len+    let size = sizeOf (undefined :: a)+    liftIO $ fillBytes ptr 0 (len * size)+    return ptr+{-# INLINE callocArray #-}++-- | 'callocArray0' @\@a@ @n@ is a continuation that provides access to a+--   pointer into a temporary block of zeroed memory sufficient to hold @n@+--   values of type @a@, along with a final terminal element.+callocArray0 :: forall a . Storable a => Int -> Codensity IO (Ptr a)+callocArray0 len = do+    ptr <- allocaArray0 len+    let size = sizeOf (undefined :: a)+    liftIO $ fillBytes ptr 0 (len * size)+    return ptr+{-# INLINE callocArray0 #-}++--++-- | 'withForeignPtr' @ptr@ is a continuation that provides safe access to the+--   backing pointer of @ptr@.+withForeignPtr :: ForeignPtr a -> Codensity IO (Ptr a)+withForeignPtr ptr = Codensity (C.withForeignPtr ptr)+{-# INLINE withForeignPtr #-}++--++-- | 'ToCString' @a@ is a class for types @a@ that can be encoded into +--   'CString's.+class ToCString a where+    -- | 'withCString' @a@ is a continuation that provides access to @a@ as a+    --   'CString'.+    withCString    :: a -> Codensity IO CString+    -- | 'withCStringLen' @a@ is a continuation that provides access to @a@ as a+    --   'CStringLen'.+    withCStringLen :: a -> Codensity IO CStringLen++instance ToCString String where+    withCString s    = Codensity (C.withCString s)+    {-# INLINE withCString #-}+    +    withCStringLen s = Codensity (C.withCStringLen s)+    {-# INLINE withCStringLen #-}++instance ToCString BS.ByteString where+    withCString s    = Codensity (BS.useAsCString s)+    {-# INLINE withCString #-}++    withCStringLen s = Codensity (BS.useAsCStringLen s)+    {-# INLINE withCStringLen #-}++instance ToCString SBS.ShortByteString where+    withCString    s = Codensity (SBS.useAsCString s)+    {-# INLINE withCString #-}++    withCStringLen s = Codensity (SBS.useAsCStringLen s)+    {-# INLINE withCStringLen #-}
src/Foreign/Marshal/ContT.hs view
@@ -30,6 +30,8 @@     -- * Reexports     , CString, CStringLen     , Ptr, nullPtr+    , ContT(..)+    , lowerContT     -- * Projected variants     -- | These variants work in the same way as their corresponding functions     --   without the terminal prime, but with a function argument that projects@@ -67,6 +69,10 @@ import           Foreign.Ptr import           Foreign.Storable +-- | Lower a 'ContT' into a computation in the base monad.+lowerContT :: (Monad m) => ContT a m a -> m a+lowerContT (ContT f) = f return+ -- | 'alloca' @\@a@ is a continuation that provides access to a pointer into a --   temporary block of memory sufficient to hold values of type @a@. alloca :: Storable a => ContT r IO (Ptr a)@@ -80,6 +86,7 @@     ptr <- alloca     liftIO $ poke ptr val     return ptr+{-# INLINE allocaWith #-}  -- | 'allocaBytes' @n@ is a continuation that provides access to a pointer into --   a temporary block of memory sufficient to hold @n@ bytes, with@@ -104,6 +111,7 @@ bracketContT :: (a -> IO b) -> (a -> IO c) -> ContT r IO a -> ContT r IO a bracketContT init' final = withContT $ \f a ->     bracket (init' a $> a) final f+{-# INLINE bracketContT #-}  -- @@ -302,10 +310,10 @@  -- --- | 'callocArray0' @\@a@ @n@ is a continuation that provides access to a+-- | 'callocArray' @\@a@ @n@ is a continuation that provides access to a --   pointer into a temporary block of zeroed memory sufficient to hold @n@ --   values of type @a@.-callocArray :: forall a r . Storable a => Int -> ContT r IO (Ptr a)+callocArray :: forall a r. Storable a => Int -> ContT r IO (Ptr a) callocArray len = do     ptr <- allocaArray len     let size = sizeOf (undefined :: a)