@@ -166,6 +166,7 @@ module Streamly.Internal.Data.Parser.ParserD
168import Control.Exception (assert, Exception)
168import Control.Exception (assert, Exception)
169+import Control.Monad (when)
169import Control.Monad.Catch (MonadCatch, MonadThrow(..))
170import Control.Monad.Catch (MonadCatch, MonadThrow(..))
170import Fusion.Plugin.Types (Fuse(..))
171import Fusion.Plugin.Types (Fuse(..))
171import Streamly.Internal.Data.Fold.Type (Fold(..))
172import Streamly.Internal.Data.Fold.Type (Fold(..))
@@ -352,6 +353,10 @@ either parser = Parser step initial extract
352-- Taking elements
353-- Taking elements
353-------------------------------------------------------------------------------
354-------------------------------------------------------------------------------
356+-- Required to fuse "take" with "many" in "chunksOf", for ghc-9.x
357+{-# ANN type Tuple'Fused Fuse #-}
358+data Tuple'Fused a b = Tuple'Fused !a !b deriving Show
355-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
360-- | See 'Streamly.Internal.Data.Parser.takeBetween'.
357-- /Pre-release/
362-- /Pre-release/
@@ -360,61 +365,69 @@ either parser = Parser step initial extract
360takeBetween :: MonadCatch m => Int -> Int -> Fold m a b -> Parser m a b
365takeBetween :: MonadCatch m => Int -> Int -> Fold m a b -> Parser m a b
361takeBetween low high (Fold fstep finitial fextract) =
366takeBetween low high (Fold fstep finitial fextract) =
363− Parser step initial extract
368+ Parser step initial (extract streamErr)
367− initial = do
372+ streamErr i =
368− res <- finitial
373+ "takeBetween: Expecting alteast " ++ show low
374+ ++ " elements, got " ++ show i
377+ "takeBetween: lower bound - " ++ show low
378+ ++ " is greater than higher bound - " ++ show high
380+ foldErr :: Int -> String
382+ "takeBetween: the collecting fold terminated after"
383+ ++ " consuming" ++ show i ++ " elements"
384+ ++ " minimum" ++ show low ++ " elements needed"
386+ -- Exactly the same as snext except different constructors, we can possibly
387+ -- deduplicate the two.
388+ {-# INLINE inext #-}
369− return $ case res of
391+ in case res of
370− FL.Partial s -> IPartial $ Tuple' 0 s
392+ FL.Partial s -> do
393+ let s1 = Tuple'Fused i1 s
395+ -- XXX ideally this should be a Continue instead
396+ then return $ IPartial s1
397+ else IDone <$> extract foldErr s1
371 FL.Done b ->
398 FL.Done b ->
372− if low <= 0
399+ return
373− then IDone b
401+ then IDone b
374− else IError
402+ else IError (foldErr i1)
375− $ "takeBetween: the collecting fold terminated without"
376− ++ " consuming any elements"
377− ++ " minimum" ++ show low ++ " elements needed"
379− step (Tuple' i s) a
404+ initial = do
380− | low > high =
405+ when (low >= 0 && high >= 0 && low > high)
382− $ ParseError
406+ $ throwM $ ParseError invalidRange
383− $ "takeBetween: lower bound - " ++ show low
407+
384− ++ " is greater than higher bound - " ++ show high
408+ finitial >>= inext (-1)
385− | high <= 0 = Done 1 <$> fextract s
409+
386− | i1 < low = do
410+ -- Keep the impl same as inext
387− res <- fstep s a
411+ {-# INLINE snext #-}
388− return
412+ snext i res =
389− $ case res of
413+ let i1 = i + 1
390− FL.Partial s1 -> Continue 0 $ Tuple' i1 s1
414+ in case res of
416+ let s1 = Tuple'Fused i1 s
418+ then return $ Continue 0 s1
419+ else Done 0 <$> extract foldErr s1
391− FL.Done _ ->
420+ FL.Done b ->
392− Error
424+ else Error (foldErr i1)
393− $ "takeBetween: the collecting fold terminated after"
394− ++ " consuming" ++ show i1 ++ " elements"
395− ++ " minimum" ++ show low ++ " elements needed"
401− then Done 0 <$> fextract s1
402− else return $ Partial 0 $ Tuple' i1 s1
403− FL.Done b -> return $ Done 0 b
407− i1 = i + 1
426+ step (Tuple'Fused i s) a = fstep s a >>= snext i
409− extract (Tuple' i s)
428+ extract f (Tuple'Fused i s)
410 | i >= low && i <= high = fextract s
429 | i >= low && i <= high = fextract s
411− | otherwise = throwM $ ParseError err
430+ | otherwise = throwM $ ParseError (f i)
416− "takeBetween: Expecting alteast " ++ show low
417− ++ " elements, got " ++ show i
419-- | See 'Streamly.Internal.Data.Parser.takeEQ'.
432-- | See 'Streamly.Internal.Data.Parser.takeEQ'.