trackProgressWithChunkSize :: Word64 -> (Word64 -> Word64 -> IO ()) ->
                              ByteString ->
                              IO ByteString
trackProgressWithChunkSize chunkSize tracker inputBS = runLoop 0  inputBS
 where
  runLoop x bstr | BS.null bstr = return BS.empty
                 | otherwise    = unsafeInterleaveIO $ do
    let (first,rest) = BS.splitAt (fromIntegral chunkSize) bstr
        amtRead      = fromIntegral (BS.length first)
    tracker amtRead (x + amtRead)
    (first `BS.append`) <$> runLoop (x + amtRead) rest

-- |Given a format string (described below), track the progress of a function.
-- The argument to the callback will be the string expanded with the given
-- progress information.
--
-- Format string items:
--
--   * %b is the number of bytes read
--
--   * %B is the number of bytes read, formatted into a human-readable string
--
--   * %c is the size of the last chunk read
--
--   * %C is the size of the last chunk read, formatted human-readably
--
--   * %r is the rate in bytes per second
--
--   * %R is the rate, formatted human-readably
--
--   * %% is the character '%'
--
-- If you provide a total size (the maybe argument, in bytes), then you may
-- also use the following items:
--
--   * %t is the estimated time to completion in seconds
--
--   * %T is the estimated time to completion, formatted as HH:MM:SS
--
--   * %p is the percentage complete
--
trackProgressWithChunkSize :: Word64 -> (Word64 -> Word64 -> IO ()) ->
                              ByteString ->
                              IO ByteString
trackProgressWithChunkSize chunkSize tracker inputBS = runLoop 0  inputBS
 where
  runLoop x bstr | BS.null bstr = return BS.empty
                 | otherwise    = unsafeInterleaveIO $ do
    let (first,rest) = BS.splitAt (fromIntegral chunkSize) bstr
        amtRead      = fromIntegral (BS.length first)
    tracker amtRead (x + amtRead)
    (first `BS.append`) <$> runLoop (x + amtRead) rest

-- |Given a format string (described below), track the progress of a function.
-- The argument to the callback will be the string expanded with the given
-- progress information.
--
-- Format string items:
--
--   * %b is the number of bytes read
--
--   * %B is the number of bytes read, formatted into a human-readable string
--
--   * %c is the size of the last chunk read
--
--   * %C is the size of the last chunk read, formatted human-readably
--
--   * %r is the rate in bytes per second
--
--   * %R is the rate, formatted human-readably
--
--   * %% is the character '%'
--
-- If you provide a total size (the maybe argument, in bytes), then you may
-- also use the following items:
--
--   * %t is the estimated time to completion in seconds
--
--   * %T is the estimated time to completion, formatted as HH:MM:SS
--
--   * %p is the percentage complete
--
trackProgressWithChunkSize chunkSize tracker inputBS = runLoop 0  inputBS
 where
  runLoop x bstr | BS.null bstr = return BS.empty
                 | otherwise    = unsafeInterleaveIO $ do
    let (first,rest) = BS.splitAt (fromIntegral chunkSize) bstr
        amtRead      = fromIntegral (BS.length first)
    tracker amtRead (x + amtRead)
    (first `BS.append`) <$> runLoop (x + amtRead) rest

-- |Given a format string (described below), track the progress of a function.
-- The argument to the callback will be the string expanded with the given
-- progress information.
--
-- Format string items:
--
--   * %b is the number of bytes read
--
--   * %B is the number of bytes read, formatted into a human-readable string
--
--   * %c is the size of the last chunk read
--
--   * %C is the size of the last chunk read, formatted human-readably
--
--   * %r is the rate in bytes per second
--
--   * %R is the rate, formatted human-readably
--
--   * %% is the character '%'
--
-- If you provide a total size (the maybe argument, in bytes), then you may
-- also use the following items:
--
--   * %t is the estimated time to completion in seconds
--
--   * %T is the estimated time to completion, formatted as HH:MM:SS
--
--   * %p is the percentage complete
--