packages feed

jvm-streaming 0.1 → 0.2

raw patch · 3 files changed

+30/−16 lines, 3 filesdep ~inline-javadep ~jnidep ~jvmnew-uploader

Dependency ranges changed: inline-java, jni, jvm

Files

jvm-streaming.cabal view
@@ -1,5 +1,5 @@ name:                jvm-streaming-version:             0.1+version:             0.2 synopsis:            Expose Java iterators as streams from the streaming package. description:         Please see README.md. homepage:            http://github.com/tweag/inline-java/tree/master/jvm-streaming#readme@@ -26,8 +26,8 @@   build-depends:     base >= 4.7 && < 5,     distributed-closure >= 0.3,-    jni >= 0.2.1,-    jvm >= 0.1,+    jni >= 0.3.0,+    jvm >= 0.2.0,     inline-java >= 0.6,     singletons >= 2.2,     streaming >= 0.1.4@@ -48,4 +48,3 @@     jvm-streaming,     streaming   default-language: Haskell2010-  extra-libraries: pthread
src/Language/Java/Streaming.hs view
@@ -20,11 +20,13 @@ module Language.Java.Streaming () where  import Control.Distributed.Closure.TH+import qualified Data.Coerce as Coerce import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Data.Int (Int64) import Data.Singletons (SomeSing(..)) import Data.Word (Word8)-import Foreign.Ptr (FunPtr, freeHaskellFunPtr, intPtrToPtr, ptrToIntPtr)+import Foreign.Ptr (FunPtr, Ptr, freeHaskellFunPtr, intPtrToPtr, ptrToIntPtr)+import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr) import qualified Foreign.JNI as JNI import Foreign.JNI.Types (jnull) import GHC.Stable@@ -41,10 +43,11 @@  isPoppableStream :: IORef (Stream (Of a) IO ()) -> IO Word8 isPoppableStream ref = do-    stream <- readIORef ref-    Streaming.uncons stream >>= \case+    readIORef ref >>= Streaming.uncons >>= \case       Nothing -> return $ fromIntegral $ fromEnum False-      Just _ -> return $ fromIntegral $ fromEnum True+      Just (x, stream) -> do+        writeIORef ref (Streaming.cons x stream)+        return $ fromIntegral $ fromEnum True  popStream :: Reflect a ty => IORef (Stream (Of a) IO ()) -> IO (J ty) popStream ref = do@@ -58,25 +61,25 @@         writeIORef ref stream'         reflect x -type JNIFun a = JNIEnv -> JObject -> IO a+type JNIFun a = JNIEnv -> Ptr JObject -> IO a  foreign import ccall "wrapper" wrapObjectFun-  :: JNIFun (J ty) -> IO (FunPtr (JNIFun (J ty)))+  :: JNIFun (Ptr (J ty)) -> IO (FunPtr (JNIFun (Ptr (J ty)))) foreign import ccall "wrapper" wrapBooleanFun   :: JNIFun Word8 -> IO (FunPtr (JNIFun Word8))  -- Export only to get a FunPtr. foreign export ccall "jvm_streaming_freeIterator" freeIterator-  :: JNIEnv -> JObject -> Int64 -> IO ()+  :: JNIEnv -> Ptr JObject -> Int64 -> IO () foreign import ccall "&jvm_streaming_freeIterator" freeIteratorPtr-  :: FunPtr (JNIEnv -> JObject -> Int64 -> IO ())+  :: FunPtr (JNIEnv -> Ptr JObject -> Int64 -> IO ())  data FunPtrTable = forall ty. FunPtrTable   { hasNextPtr :: FunPtr (JNIFun Word8)-  , nextPtr :: FunPtr (JNIFun (J ty))+  , nextPtr :: FunPtr (JNIFun (Ptr (J ty)))   } -freeIterator :: JNIEnv -> JObject -> Int64 -> IO ()+freeIterator :: JNIEnv -> Ptr JObject -> Int64 -> IO () freeIterator _ _ ptr = do     let sptr = castPtrToStablePtr $ intPtrToPtr $ fromIntegral ptr     FunPtrTable{..} <- deRefStablePtr sptr@@ -91,7 +94,9 @@ newIterator stream = do     ref <- newIORef stream     hasNextPtr <- wrapBooleanFun $ \_ _ -> isPoppableStream ref-    nextPtr <- wrapObjectFun $ \_ _ -> popStream ref+    nextPtr <- wrapObjectFun $ \_ _ ->+      -- Conversion is safe, because result is always a reflected object.+      unsafeForeignPtrToPtr <$> Coerce.coerce <$> popStream ref     -- Keep FunPtr's in a table that can be referenced from the Java side, so     -- that they can be freed.     tblPtr :: Int64 <- fromIntegral . ptrToIntPtr . castStablePtrToPtr <$> newStablePtr FunPtrTable{..}@@ -136,7 +141,10 @@   type instance Interp (Stream (Of a) m r) = 'Iface "java.util.Iterator"    instance Reify a ty => Reify (Stream (Of a) IO ()) ('Iface "java.util.Iterator") where-    reify it = return $ Streaming.untilRight $ do+    reify itLocal = do+      -- We make sure the iterator remains valid while we reference it.+      it <- JNI.newGlobalRef itLocal+      return $ Streaming.untilRight $ do         call it "hasNext" [] >>= \case           False -> return (Right ())           True -> do
tests/Language/Java/StreamingSpec.hs view
@@ -4,6 +4,7 @@ module Language.Java.StreamingSpec where  import Data.Int+import Data.IORef import Language.Java import Language.Java.Inline import Language.Java.Streaming ()@@ -34,3 +35,9 @@         iterator <- reflect (Streaming.each [1..10000] :: Stream (Of Int32) IO ())         stream <- reify iterator         Streaming.toList_ stream `shouldReturn` [1..10000 :: Int32]+      it "don't redo effects" $ do+        ref <- newIORef (1 :: Int32)+        iterator <- reflect $+          Streaming.replicateM 10 $ atomicModifyIORef ref (\i -> (i + 1, i))+        stream <- reify iterator+        Streaming.toList_ stream `shouldReturn` [1..10 :: Int32]