+
+
+-- | Improper isomorphism between a 'Producer' of 'ByteString's and 'Word8's
+packChars :: Monad m => Iso' (Producer Char m x) (Producer Text m x)
+packChars = Data.Profunctor.dimap to (fmap from)
+ where
+ -- to :: Monad m => Producer Char m x -> Producer Text m x
+ to p = PG.folds step id done (p^.PG.chunksOf defaultChunkSize)
+
+ step diffAs c = diffAs . (c:)
+
+ done diffAs = T.pack (diffAs [])
+
+ -- from :: Monad m => Producer Text m x -> Producer Char m x
+ from p = for p (each . T.unpack)
+{-# INLINABLE packChars #-}
+
+
+-- | Split a text stream into 'FreeT'-delimited text streams of fixed size
+chunksOf
+ :: (Monad m, Integral n)
+ => n -> Lens' (Producer Text m r)
+ (FreeT (Producer Text m) m r)
+chunksOf n k p0 = fmap concats (k (FreeT (go p0)))
+ where
+ go p = do
+ x <- next p
+ return $ case x of
+ Left r -> Pure r
+ Right (txt, p') -> Free $ do
+ p'' <- (yield txt >> p') ^. splitAt n
+ return $ FreeT (go p'')
+{-# INLINABLE chunksOf #-}
+
+
+{-| Split a text stream into sub-streams delimited by characters that satisfy the
+ predicate
+-}
+splitsWith
+ :: (Monad m)
+ => (Char -> Bool)
+ -> Producer Text m r
+ -> FreeT (Producer Text m) m r
+splitsWith predicate p0 = FreeT (go0 p0)
+ where
+ go0 p = do
+ x <- next p
+ case x of
+ Left r -> return (Pure r)
+ Right (txt, p') ->
+ if (T.null txt)
+ then go0 p'
+ else return $ Free $ do
+ p'' <- (yield txt >> p') ^. span (not . predicate)
+ return $ FreeT (go1 p'')
+ go1 p = do
+ x <- nextChar p
+ return $ case x of
+ Left r -> Pure r
+ Right (_, p') -> Free $ do
+ p'' <- p' ^. span (not . predicate)
+ return $ FreeT (go1 p'')
+{-# INLINABLE splitsWith #-}
+
+-- | Split a text stream using the given 'Char' as the delimiter
+splits :: (Monad m)
+ => Char
+ -> Lens' (Producer Text m r)
+ (FreeT (Producer Text m) m r)
+splits c k p =
+ fmap (PG.intercalates (yield (T.singleton c))) (k (splitsWith (c ==) p))
+{-# INLINABLE splits #-}
+
+{-| Isomorphism between a stream of 'Text' and groups of equivalent 'Char's , using the
+ given equivalence relation
+-}
+groupsBy
+ :: Monad m
+ => (Char -> Char -> Bool)
+ -> Lens' (Producer Text m x) (FreeT (Producer Text m) m x)
+groupsBy equals k p0 = fmap concats (k (FreeT (go p0))) where
+ go p = do x <- next p
+ case x of Left r -> return (Pure r)
+ Right (bs, p') -> case T.uncons bs of
+ Nothing -> go p'
+ Just (c, _) -> do return $ Free $ do
+ p'' <- (yield bs >> p')^.span (equals c)
+ return $ FreeT (go p'')
+{-# INLINABLE groupsBy #-}
+
+
+-- | Like 'groupsBy', where the equality predicate is ('==')
+groups
+ :: Monad m
+ => Lens' (Producer Text m x) (FreeT (Producer Text m) m x)
+groups = groupsBy (==)
+{-# INLINABLE groups #-}
+
+
+
+{-| Split a text stream into 'FreeT'-delimited lines
+-}
+lines
+ :: (Monad m) => Iso' (Producer Text m r) (FreeT (Producer Text m) m r)
+lines = Data.Profunctor.dimap _lines (fmap _unlines)
+ where
+ _lines p0 = FreeT (go0 p0)
+ where
+ go0 p = do
+ x <- next p
+ case x of
+ Left r -> return (Pure r)
+ Right (txt, p') ->
+ if (T.null txt)
+ then go0 p'
+ else return $ Free $ go1 (yield txt >> p')
+ go1 p = do
+ p' <- p ^. break ('\n' ==)
+ return $ FreeT $ do
+ x <- nextChar p'
+ case x of
+ Left r -> return $ Pure r
+ Right (_, p'') -> go0 p''
+ -- _unlines
+ -- :: Monad m
+ -- => FreeT (Producer Text m) m x -> Producer Text m x
+ _unlines = concats . PG.maps (<* yield (T.singleton '\n'))
+
+
+{-# INLINABLE lines #-}
+
+
+-- | Split a text stream into 'FreeT'-delimited words
+words
+ :: (Monad m) => Iso' (Producer Text m r) (FreeT (Producer Text m) m r)
+words = Data.Profunctor.dimap go (fmap _unwords)
+ where
+ go p = FreeT $ do
+ x <- next (p >-> dropWhile isSpace)
+ return $ case x of
+ Left r -> Pure r
+ Right (bs, p') -> Free $ do
+ p'' <- (yield bs >> p') ^. break isSpace
+ return (go p'')
+ _unwords = PG.intercalates (yield $ T.singleton ' ')
+
+{-# INLINABLE words #-}
+
+