summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoe Crayne <joe@jerkface.net>2018-10-23 21:33:48 -0400
committerJoe Crayne <joe@jerkface.net>2018-10-23 21:33:48 -0400
commitd62577cf423148a2a07eac33377003802e7e70d6 (patch)
treea98344ba944f6f47583ee89b178e0e7327483bf4
parent185c1f9e85fd0a2d3bb5f0531a652fa4787fba25 (diff)
More PrimMonad work.
-rw-r--r--haskell/Data/XDelta.hsc89
1 files changed, 71 insertions, 18 deletions
diff --git a/haskell/Data/XDelta.hsc b/haskell/Data/XDelta.hsc
index 09f5523..113959b 100644
--- a/haskell/Data/XDelta.hsc
+++ b/haskell/Data/XDelta.hsc
@@ -2,8 +2,9 @@
2{-# LANGUAGE GADTs #-} 2{-# LANGUAGE GADTs #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-} 3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
4{-# LANGUAGE LambdaCase #-} 4{-# LANGUAGE LambdaCase #-}
5{-# LANGUAGE PatternSynonyms #-}
6{-# LANGUAGE NondecreasingIndentation #-} 5{-# LANGUAGE NondecreasingIndentation #-}
6{-# LANGUAGE PatternSynonyms #-}
7{-# LANGUAGE RankNTypes #-}
7module Data.XDelta where 8module Data.XDelta where
8 9
9import Control.Monad 10import Control.Monad
@@ -15,6 +16,7 @@ import qualified Data.ByteString as B
15import qualified Data.ByteString.Unsafe as B 16import qualified Data.ByteString.Unsafe as B
16import qualified Data.ByteString.Internal as B 17import qualified Data.ByteString.Internal as B
17import Data.Coerce 18import Data.Coerce
19import Data.Monoid
18import Data.Primitive.Addr 20import Data.Primitive.Addr
19import Data.Primitive.ByteArray 21import Data.Primitive.ByteArray
20import Data.Primitive.MutVar 22import Data.Primitive.MutVar
@@ -23,9 +25,11 @@ import qualified Data.Text as T
23import Data.Text.Encoding 25import Data.Text.Encoding
24import Data.Word 26import Data.Word
25import Foreign.C.Types 27import Foreign.C.Types
28import Foreign.C.String
26import Foreign.ForeignPtr (withForeignPtr) 29import Foreign.ForeignPtr (withForeignPtr)
27import Foreign.Ptr 30import Foreign.Ptr
28import Foreign.Concurrent 31import Foreign.Concurrent
32import Foreign.Storable
29import Foreign.ForeignPtr (ForeignPtr) 33import Foreign.ForeignPtr (ForeignPtr)
30import GHC.Exts 34import GHC.Exts
31 35
@@ -164,12 +168,13 @@ set_source stream nm blksz maxwinsz = do
164 unsafeIOToPrim (xd3_set_source strm srcptr) 168 unsafeIOToPrim (xd3_set_source strm srcptr)
165 writeMutVar (streamSource stream) (Just src) 169 writeMutVar (streamSource stream) (Just src)
166 170
167data XDeltaMethods m = XDeltaMethods 171data XDeltaMethods m u = XDeltaMethods
168 { xConfig :: Config 172 { xConfig :: Config
169 , xGetSource :: Xoff_t -> B.ByteString 173 , xGetSource :: Xoff_t -> B.ByteString
170 , xOutput :: Ptr Word8 -> Int -> IO m 174 , xOutput :: Ptr Word8 -> Int -> m u
171 , xOnError :: ErrorCode -> String -> IO m 175 , xOnError :: ErrorCode -> String -> m u
172 , xBlockSize :: Usize_t 176 , xBlockSize :: Usize_t
177 , xInterleave :: forall a. m a -> m a
173 } 178 }
174 179
175-- | Checks for legal flag changes. 180-- | Checks for legal flag changes.
@@ -181,35 +186,84 @@ setFlush stream wantFlush = return () -- todo
181setSkipWindow :: PrimMonad m => Stream m -> Bool -> m () 186setSkipWindow :: PrimMonad m => Stream m -> Bool -> m ()
182setSkipWindow stream wantSkipWin = return () -- todo 187setSkipWindow stream wantSkipWin = return () -- todo
183 188
184{- 189foreign import ccall "xdelta3.h xd3_avail_input" xd3_avail_input :: Ptr Xd3Stream -> Ptr a -> Usize_t -> IO ()
185xdelta :: Monoid m => XDeltaMethods m -> (Stream s -> IO ErrorCode) -> [B.ByteString] -> ST s m 190
191avail_input stream p sz =
192 -- withForeignPtr fp (\stream -> xd3_avail_input stream p sz)
193 -- TODO
194 return ()
195
196-- | This acknowledges receipt of output data, must be called after any
197-- XD3_OUTPUT return.
198foreign import ccall "xdelta3.h xd3_consume_output" xd3_consume_output :: Ptr Xd3Stream -> IO ()
199
200nextOut :: PrimMonad m => Stream m -> ((Ptr Word8, Int) -> m a) -> m a
201nextOut stream action = do
202 buf <- (,)
203 <$> readAtByte (streamArray stream) #{offset xd3_stream, next_out}
204 <*> readAtByte (streamArray stream) #{offset xd3_stream, avail_out}
205 a <- action buf
206 unsafeIOToPrim $ xd3_consume_output (ptr $ mutableByteArrayContents $ streamArray stream)
207 return a
208
209
210requestedBlockNumber :: PrimMonad m => Stream m -> m (Maybe Xoff_t)
211requestedBlockNumber stream = do
212 msrc <- readMutVar $ streamSource stream
213 forM msrc $ \src -> readAtByte src #offset xd3_source, getblkno
214
215data CurrentBlock = CurrentBlock
216 { blkno :: !Xoff_t -- ^ current block number
217 , blkSize :: !Usize_t -- ^ number of bytes on current block: must be >= 0 and <= 'srcBlockSize'
218 , blkPtr :: !(Ptr Word8) -- ^ current block array
219 }
220
221foreign import ccall "xdelta3.h xd3_errstring" xd3_errstring :: Ptr Xd3Stream -> IO CString
222
223-- | Gives some extra information about the latest library error, if any
224-- is known.
225errorString stream = unsafeIOToPrim $ withForeignPtr (streamPtr stream) $ \stream -> do
226 cstring <- xd3_errstring stream
227 peekCString cstring
228
229pokeCurrentBlock :: PrimMonad m => Stream m -> CurrentBlock -> m ()
230pokeCurrentBlock stream (CurrentBlock no sz ptr) = do
231 msrc <- readMutVar $ streamSource stream
232 forM_ msrc $ \src -> do
233 writeAtByte src #{offset xd3_source, curblkno} no
234 writeAtByte src #{offset xd3_source, onblk} sz
235 writeAtByte src #{offset xd3_source, curblk} ptr
236
237
238xdelta :: (PrimBase m, Monoid u) => XDeltaMethods m u -> (Stream m -> IO ErrorCode) -> [B.ByteString]
239 -> m (Either ErrorCode u)
186xdelta x xxcode_input ds = do 240xdelta x xxcode_input ds = do
187 mstream <- config_stream (xConfig x) 241 mstream <- config_stream (xConfig x)
188 forM_ mstream $ \stream -> do 242 forM mstream $ \stream -> do
189 set_source stream "xdelta" (xBlockSize x) (xBlockSize x) 243 set_source stream "xdelta" (xBlockSize x) (xBlockSize x)
190 let go withBlk (d:ds) = do 244 let go withBlk (d:ds) = do
191 let (fp,off,len) = B.toForeignPtr d 245 let (fp,off,len) = B.toForeignPtr d
192 withForeignPtr fp $ \indata0 -> do 246 eof = null ds
247 when eof $ setFlush stream True
248 unsafeIOToPrim $ withForeignPtr fp $ \indata0 -> do
193 let indata = indata0 `plusPtr` off 249 let indata = indata0 `plusPtr` off
194 eof = null ds
195 when eof $ xd3_set_flags (ptr $ mutableByteArrayContents $ streamArray stream) XD3_FLUSH
196 avail_input stream indata (fromIntegral len) 250 avail_input stream indata (fromIntegral len)
197 go2 withBlk eof ds 251 unsafePrimToIO $ go2 withBlk eof ds
198 go2 withBlk eof ds = do 252 go2 withBlk eof ds = do
199 ret <- withBlk $ xxcode_input stream 253 ret <- withBlk $ unsafeIOToPrim $ xxcode_input stream
200 case ret of 254 case ret of
201 XD3_INPUT -> if (not eof) then go withBlk ds else return mempty 255 XD3_INPUT -> if (not eof) then go withBlk ds else return mempty
202 XD3_OUTPUT -> do 256 XD3_OUTPUT -> do
203 m' <- nextOut stream (uncurry $ xOutput x) 257 m' <- nextOut stream (uncurry $ xOutput x)
204 ms <- unsafeInterleaveIO $ go2 withBlk eof ds 258 ms <- xInterleave x $ go2 withBlk eof ds
205 return $ m' <> ms 259 return $ m' <> ms
206 XD3_GETSRCBLK -> do 260 XD3_GETSRCBLK -> do
207 n <- requestedBlockNumber stream 261 Just n <- requestedBlockNumber stream
208 let blk = xGetSource x n 262 let blk = xGetSource x n
209 withBlk' act = let (fp,off,len) = B.toForeignPtr blk 263 withBlk' act = let (fp,off,len) = B.toForeignPtr blk
210 in withForeignPtr fp $ \p -> do 264 in unsafeIOToPrim $ withForeignPtr fp $ \p -> unsafePrimToIO $ do
211 pokeCurrentBlock stream $ CurrentBlock n (fromIntegral len) (plusPtr p off) 265 pokeCurrentBlock stream $ CurrentBlock n (fromIntegral len) (plusPtr p off)
212 act 266 act
213 go2 withBlk' eof ds 267 go2 withBlk' eof ds
214 XD3_GOTHEADER -> go2 withBlk eof ds -- No 268 XD3_GOTHEADER -> go2 withBlk eof ds -- No
215 XD3_WINSTART -> go2 withBlk eof ds -- action 269 XD3_WINSTART -> go2 withBlk eof ds -- action
@@ -222,4 +276,3 @@ xdelta x xxcode_input ds = do
222 s <- errorString stream 276 s <- errorString stream
223 xOnError x e s 277 xOnError x e s
224 go id ds 278 go id ds
225-}