{-# LANGUAGE LambdaCase #-}

-- | Lazy 'TL.Text' as @Mu (Cons StrictText)@.
--
-- Lazy Text is internally a linked list of strict chunks:
--
-- @
-- data Text = Empty | Chunk !StrictText Text
-- @
--
-- This is exactly @Fix (Cons StrictText)@. This module provides
-- conversions and operations that let you apply the full recursion
-- scheme and streaming metamorphism infrastructure to lazy Text.
module Data.Fmt.Text.Lazy (
    -- * Conversion
    toChunks,
    fromChunks,
    toNuChunks,

    -- * Folding
    foldChunks,

    -- * Unfolding
    unfoldChunks,

    -- * Refold
    refoldChunks,

    -- * Mapping
    mapChunks,

    -- * Streaming
    streamChunks,
    transformChunks,
) where

import Data.Text (Text)
import qualified Data.Text.Lazy as TL
import qualified Data.Text.Internal.Lazy as TLI
import Data.Functor.Fixed (Mu, Nu (..), unwrap, Algebra, Coalgebra)
import Data.Functor.Foldable (fold, unfold, refold, comap)
import Data.Functor.Pattern (Cons (..))

---------------------------------------------------------------------
-- Conversion
---------------------------------------------------------------------

-- | View a lazy 'TL.Text' as @Mu (Cons Text)@.
--
-- Each 'Cons' layer holds one strict chunk.
--
-- O(n) — rebuilds the spine as a Church-encoded list.
toChunks :: TL.Text -> Mu (Cons Text)
toChunks :: Text -> Mu (Cons Text)
toChunks = Coalgebra (Cons Text) Text -> Text -> Mu (Cons Text)
forall (f :: * -> *) a. Functor f => Coalgebra f a -> a -> Mu f
unfold Coalgebra (Cons Text) Text
coalg
  where
    coalg :: Coalgebra (Cons Text) Text
coalg Text
lt = case Text
lt of
        Text
TLI.Empty -> Cons Text Text
forall a b. Cons a b
Nil
        TLI.Chunk Text
c Text
rest -> Text -> Coalgebra (Cons Text) Text
forall a b. a -> b -> Cons a b
Cons Text
c Text
rest

-- | Reassemble a @Mu (Cons Text)@ into a lazy 'TL.Text'.
--
-- O(n) — folds the Church-encoded list back into chunks.
fromChunks :: Mu (Cons Text) -> TL.Text
fromChunks :: Mu (Cons Text) -> Text
fromChunks = Algebra (Cons Text) Text -> Mu (Cons Text) -> Text
forall (f :: * -> *) a. Algebra f a -> Mu f -> a
fold Algebra (Cons Text) Text
alg
  where
    alg :: Algebra (Cons Text) Text
alg Cons Text Text
Nil = Text
TL.empty
    alg (Cons Text
c Text
rest) = Text -> Text -> Text
TLI.Chunk Text
c Text
rest

-- | View a lazy 'TL.Text' as @Nu (Cons Text)@ for lazy streaming.
-- O(1) construction — the Text itself is the seed.
toNuChunks :: TL.Text -> Nu (Cons Text)
toNuChunks :: Text -> Nu (Cons Text)
toNuChunks = Coalgebra (Cons Text) Text -> Text -> Nu (Cons Text)
forall (f :: * -> *) a. (a -> f a) -> a -> Nu f
Nu Coalgebra (Cons Text) Text
coalg
  where
    coalg :: Coalgebra (Cons Text) Text
coalg Text
lt = case Text
lt of
        Text
TLI.Empty -> Cons Text Text
forall a b. Cons a b
Nil
        TLI.Chunk Text
c Text
rest -> Text -> Coalgebra (Cons Text) Text
forall a b. a -> b -> Cons a b
Cons Text
c Text
rest

---------------------------------------------------------------------
-- Folding
---------------------------------------------------------------------

-- | Fold a lazy 'TL.Text' chunk by chunk.
--
-- @foldChunks alg = fold alg . toChunks@
foldChunks :: Algebra (Cons Text) a -> TL.Text -> a
foldChunks :: forall a. Algebra (Cons Text) a -> Text -> a
foldChunks Algebra (Cons Text) a
alg = Algebra (Cons Text) a -> Mu (Cons Text) -> a
forall (f :: * -> *) a. Algebra f a -> Mu f -> a
fold Algebra (Cons Text) a
alg (Mu (Cons Text) -> a) -> (Text -> Mu (Cons Text)) -> Text -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Mu (Cons Text)
toChunks

---------------------------------------------------------------------
-- Unfolding
---------------------------------------------------------------------

-- | Build a lazy 'TL.Text' from a seed, one chunk at a time.
--
-- @unfoldChunks coalg = fromChunks . unfold coalg@
unfoldChunks :: Coalgebra (Cons Text) a -> a -> TL.Text
unfoldChunks :: forall a. Coalgebra (Cons Text) a -> a -> Text
unfoldChunks Coalgebra (Cons Text) a
coalg = Mu (Cons Text) -> Text
fromChunks (Mu (Cons Text) -> Text) -> (a -> Mu (Cons Text)) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Coalgebra (Cons Text) a -> a -> Mu (Cons Text)
forall (f :: * -> *) a. Functor f => Coalgebra f a -> a -> Mu f
unfold Coalgebra (Cons Text) a
coalg

---------------------------------------------------------------------
-- Refold
---------------------------------------------------------------------

-- | Unfold then fold, fused — no intermediate @Mu@ structure.
refoldChunks :: Algebra (Cons Text) b -> Coalgebra (Cons Text) a -> a -> b
refoldChunks :: forall b a.
Algebra (Cons Text) b -> Coalgebra (Cons Text) a -> a -> b
refoldChunks = Algebra (Cons Text) b -> Coalgebra (Cons Text) a -> a -> b
forall (f :: * -> *) b a.
Functor f =>
Algebra f b -> Coalgebra f a -> a -> b
refold

---------------------------------------------------------------------
-- Mapping
---------------------------------------------------------------------

-- | Map a function over each strict chunk.
mapChunks :: (Text -> Text) -> TL.Text -> TL.Text
mapChunks :: (Text -> Text) -> Text -> Text
mapChunks Text -> Text
f = Mu (Cons Text) -> Text
fromChunks (Mu (Cons Text) -> Text)
-> (Text -> Mu (Cons Text)) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Text -> Text) -> Mu (Cons Text) -> Mu (Cons Text)
forall (f :: * -> * -> *) a b.
(Bifunctor f, Functor (f a), Functor (f b)) =>
(a -> b) -> Mu (f a) -> Mu (f b)
comap Text -> Text
f (Mu (Cons Text) -> Mu (Cons Text))
-> (Text -> Mu (Cons Text)) -> Text -> Mu (Cons Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Mu (Cons Text)
toChunks

---------------------------------------------------------------------
-- Streaming
---------------------------------------------------------------------

-- | Apply a streaming transformation to the chunks.
streamChunks
    :: (Mu (Cons Text) -> Mu (Cons Text))
    -> TL.Text -> TL.Text
streamChunks :: (Mu (Cons Text) -> Mu (Cons Text)) -> Text -> Text
streamChunks Mu (Cons Text) -> Mu (Cons Text)
f = Mu (Cons Text) -> Text
fromChunks (Mu (Cons Text) -> Text)
-> (Text -> Mu (Cons Text)) -> Text -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mu (Cons Text) -> Mu (Cons Text)
f (Mu (Cons Text) -> Mu (Cons Text))
-> (Text -> Mu (Cons Text)) -> Text -> Mu (Cons Text)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Mu (Cons Text)
toChunks

-- | Apply a streaming transformation that changes the element type.
transformChunks
    :: (Mu (Cons Text) -> Mu (Cons a))
    -> TL.Text -> [a]
transformChunks :: forall a. (Mu (Cons Text) -> Mu (Cons a)) -> Text -> [a]
transformChunks Mu (Cons Text) -> Mu (Cons a)
f = Cons a (Mu (Cons a)) -> [a]
forall {a}. Cons a (Mu (Cons a)) -> [a]
go (Cons a (Mu (Cons a)) -> [a])
-> (Text -> Cons a (Mu (Cons a))) -> Text -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mu (Cons a) -> Cons a (Mu (Cons a))
forall (f :: * -> *). Functor f => Mu f -> f (Mu f)
unwrap (Mu (Cons a) -> Cons a (Mu (Cons a)))
-> (Text -> Mu (Cons a)) -> Text -> Cons a (Mu (Cons a))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Mu (Cons Text) -> Mu (Cons a)
f (Mu (Cons Text) -> Mu (Cons a))
-> (Text -> Mu (Cons Text)) -> Text -> Mu (Cons a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> Mu (Cons Text)
toChunks
  where
    go :: Cons a (Mu (Cons a)) -> [a]
go Cons a (Mu (Cons a))
Nil = []
    go (Cons a
a Mu (Cons a)
rest) = a
a a -> [a] -> [a]
forall a. a -> [a] -> [a]
: Cons a (Mu (Cons a)) -> [a]
go (Mu (Cons a) -> Cons a (Mu (Cons a))
forall (f :: * -> *). Functor f => Mu f -> f (Mu f)
unwrap Mu (Cons a)
rest)