diff options
author | Joe Crayne <joe@jerkface.net> | 2018-10-23 21:33:48 -0400 |
---|---|---|
committer | Joe Crayne <joe@jerkface.net> | 2018-10-23 21:33:48 -0400 |
commit | d62577cf423148a2a07eac33377003802e7e70d6 (patch) | |
tree | a98344ba944f6f47583ee89b178e0e7327483bf4 | |
parent | 185c1f9e85fd0a2d3bb5f0531a652fa4787fba25 (diff) |
More PrimMonad work.
-rw-r--r-- | haskell/Data/XDelta.hsc | 89 |
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 #-} | ||
7 | module Data.XDelta where | 8 | module Data.XDelta where |
8 | 9 | ||
9 | import Control.Monad | 10 | import Control.Monad |
@@ -15,6 +16,7 @@ import qualified Data.ByteString as B | |||
15 | import qualified Data.ByteString.Unsafe as B | 16 | import qualified Data.ByteString.Unsafe as B |
16 | import qualified Data.ByteString.Internal as B | 17 | import qualified Data.ByteString.Internal as B |
17 | import Data.Coerce | 18 | import Data.Coerce |
19 | import Data.Monoid | ||
18 | import Data.Primitive.Addr | 20 | import Data.Primitive.Addr |
19 | import Data.Primitive.ByteArray | 21 | import Data.Primitive.ByteArray |
20 | import Data.Primitive.MutVar | 22 | import Data.Primitive.MutVar |
@@ -23,9 +25,11 @@ import qualified Data.Text as T | |||
23 | import Data.Text.Encoding | 25 | import Data.Text.Encoding |
24 | import Data.Word | 26 | import Data.Word |
25 | import Foreign.C.Types | 27 | import Foreign.C.Types |
28 | import Foreign.C.String | ||
26 | import Foreign.ForeignPtr (withForeignPtr) | 29 | import Foreign.ForeignPtr (withForeignPtr) |
27 | import Foreign.Ptr | 30 | import Foreign.Ptr |
28 | import Foreign.Concurrent | 31 | import Foreign.Concurrent |
32 | import Foreign.Storable | ||
29 | import Foreign.ForeignPtr (ForeignPtr) | 33 | import Foreign.ForeignPtr (ForeignPtr) |
30 | import GHC.Exts | 34 | import 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 | ||
167 | data XDeltaMethods m = XDeltaMethods | 171 | data 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 | |||
181 | setSkipWindow :: PrimMonad m => Stream m -> Bool -> m () | 186 | setSkipWindow :: PrimMonad m => Stream m -> Bool -> m () |
182 | setSkipWindow stream wantSkipWin = return () -- todo | 187 | setSkipWindow stream wantSkipWin = return () -- todo |
183 | 188 | ||
184 | {- | 189 | foreign import ccall "xdelta3.h xd3_avail_input" xd3_avail_input :: Ptr Xd3Stream -> Ptr a -> Usize_t -> IO () |
185 | xdelta :: Monoid m => XDeltaMethods m -> (Stream s -> IO ErrorCode) -> [B.ByteString] -> ST s m | 190 | |
191 | avail_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. | ||
198 | foreign import ccall "xdelta3.h xd3_consume_output" xd3_consume_output :: Ptr Xd3Stream -> IO () | ||
199 | |||
200 | nextOut :: PrimMonad m => Stream m -> ((Ptr Word8, Int) -> m a) -> m a | ||
201 | nextOut 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 | |||
210 | requestedBlockNumber :: PrimMonad m => Stream m -> m (Maybe Xoff_t) | ||
211 | requestedBlockNumber stream = do | ||
212 | msrc <- readMutVar $ streamSource stream | ||
213 | forM msrc $ \src -> readAtByte src #offset xd3_source, getblkno | ||
214 | |||
215 | data 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 | |||
221 | foreign 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. | ||
225 | errorString stream = unsafeIOToPrim $ withForeignPtr (streamPtr stream) $ \stream -> do | ||
226 | cstring <- xd3_errstring stream | ||
227 | peekCString cstring | ||
228 | |||
229 | pokeCurrentBlock :: PrimMonad m => Stream m -> CurrentBlock -> m () | ||
230 | pokeCurrentBlock 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 | |||
238 | xdelta :: (PrimBase m, Monoid u) => XDeltaMethods m u -> (Stream m -> IO ErrorCode) -> [B.ByteString] | ||
239 | -> m (Either ErrorCode u) | ||
186 | xdelta x xxcode_input ds = do | 240 | xdelta 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 | -} | ||