-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Builder for Text and ByteString based on linear types -- -- Strict Text and ByteString builder, which hides mutable buffer behind -- linear types and takes amortized linear time. @package text-builder-linear @version 0.1.2 -- | Low-level routines for Buffer manipulations. module Data.Text.Builder.Linear.Core -- | Internally Buffer is a mutable buffer. If a client gets hold of -- a variable of type Buffer, they'd be able to pass a mutable -- buffer to concurrent threads. That's why API below is carefully -- designed to prevent such possibility: clients always work with linear -- functions Buffer ⊸ Buffer instead and run them on an -- empty Buffer to extract results. -- -- In terms of linear-base Buffer is -- Consumable (see consumeBuffer) and -- Dupable (see dupBuffer), but not -- Movable. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -- -- >>> import Data.Text.Builder.Linear.Buffer -- -- >>> runBuffer (\b -> '!' .<| "foo" <| (b |> "bar" |>. '.')) -- "!foobar." ---- -- Remember: this is a strict builder, so on contrary to -- Data.Text.Lazy.Builder for optimal performance you should use -- strict left folds instead of lazy right ones. -- -- Buffer is an unlifted datatype, so you can put it into an -- unboxed tuple (# ..., ... #), but not into (..., -- ...). data Buffer :: TYPE ('BoxedRep 'Unlifted) -- | Run a linear function on an empty Buffer, producing a strict -- Text. -- -- Be careful to write runBuffer (\b -> ...) instead of -- runBuffer $ \b -> ..., because current implementation of -- linear types lacks special support for ($). Another option is -- to enable {-# LANGUAGE BlockArguments #-} and write -- runBuffer \b -> .... Alternatively, you can import -- ($) from linear-base. -- -- runBuffer is similar in spirit to mutable arrays API in -- Data.Array.Mutable.Linear, which provides functions -- like fromList ∷ [a] → (Vector -- a ⊸ Ur b) ⊸ Ur b. -- Here the initial buffer is always empty and b is Text. -- Since Text is Movable, Text and -- Ur Text are equivalent. runBuffer :: (Buffer %1 -> Buffer) %1 -> Text -- | Same as runBuffer, but returning a UTF-8 encoded strict -- ByteString. runBufferBS :: (Buffer %1 -> Buffer) %1 -> ByteString -- | Duplicate builder. Feel free to process results in parallel threads. -- Similar to Dupable from linear-base. -- -- It is a bit tricky to use because of current limitations of -- linear types with regards to let and where. E. g., -- one cannot write -- --
-- let (# b1, b2 #) = dupBuffer b in ("foo" <| b1) >< (b2 |> "bar")
--
--
-- Instead write:
--
--
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> runBuffer (\b -> case dupBuffer b of (# b1, b2 #) -> ("foo" <| b1) >< (b2 |> "bar"))
-- "foobar"
--
--
-- Note the unboxed tuple: Buffer is an unlifted datatype, so it
-- cannot be put into (..., ...).
dupBuffer :: Buffer %1 -> (# Buffer, Buffer #)
-- | Consume buffer linearly, similar to Consumable from
-- linear-base.
consumeBuffer :: Buffer %1 -> ()
-- | Erase buffer's content, replacing it with an empty Text.
eraseBuffer :: Buffer %1 -> Buffer
-- | Return buffer's size in bytes (not in Chars). This could
-- be useful to implement a lazy builder atop of a strict one.
byteSizeOfBuffer :: Buffer %1 -> (# Buffer, Word #)
-- | Return buffer's length in Chars (not in bytes). This could be
-- useful to implement dropEndBuffer and takeEndBuffer,
-- e. g.,
--
-- -- import Data.Unrestricted.Linear -- -- dropEndBuffer :: Word -> Buffer %1 -> Buffer -- dropEndBuffer n buf = case lengthOfBuffer buf of -- (# buf', len #) -> case move len of -- Ur len' -> takeBuffer (len' - n) buf' --lengthOfBuffer :: Buffer %1 -> (# Buffer, Word #) -- | Slice Buffer by dropping given number of Chars. dropBuffer :: Word -> Buffer %1 -> Buffer -- | Slice Buffer by taking given number of Chars. takeBuffer :: Word -> Buffer %1 -> Buffer -- | Create an empty Buffer. -- -- The first Buffer is the input and the second is a new empty -- Buffer. -- -- This function is needed in some situations, e.g. with -- justifyRight. The following example creates a utility function -- that justify a text and then append it to a buffer. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> import Data.Text (Text)
--
-- >>> :{
-- appendJustified :: Buffer %1 -> Text -> Buffer
-- appendJustified b t = case newEmptyBuffer b of
-- -- Note that we need to create a new buffer from the text, in order
-- -- to justify only the text and not the input buffer.
-- (# b', empty #) -> b' >< justifyRight 12 ' ' (empty |> t)
-- :}
--
--
-- -- >>> runBuffer (\b -> (b |> "Test:") `appendJustified` "foo" `appendJustified` "bar") -- "Test: foo bar" ---- -- Note: a previous buffer is necessary in order to create an empty -- buffer with the same characteristics. newEmptyBuffer :: Buffer %1 -> (# Buffer, Buffer #) -- | Low-level routine to append data of unknown size to a Buffer. appendBounded :: Int -> (forall s. MArray s -> Int -> ST s Int) -> Buffer %1 -> Buffer -- | Low-level routine to append data of known size to a Buffer. appendExact :: Int -> (forall s. MArray s -> Int -> ST s ()) -> Buffer %1 -> Buffer -- | Low-level routine to prepend data of unknown size to a Buffer. prependBounded :: Int -> (forall s. MArray s -> Int -> ST s Int) -> (forall s. MArray s -> Int -> ST s Int) -> Buffer %1 -> Buffer -- | Low-level routine to append data of known size to a Buffer. prependExact :: Int -> (forall s. MArray s -> Int -> ST s ()) -> Buffer %1 -> Buffer -- | Concatenate two Buffers, potentially mutating both of them. -- -- You likely need to use dupBuffer to get hold on two builders at -- once: -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> runBuffer (\b -> case dupBuffer b of (# b1, b2 #) -> ("foo" <| b1) >< (b2 |> "bar"))
-- "foobar"
--
(><) :: Buffer %1 -> Buffer %1 -> Buffer
infix 6 ><
-- | Buffer for strict Text, based on linear types.
module Data.Text.Builder.Linear.Buffer
-- | Internally Buffer is a mutable buffer. If a client gets hold of
-- a variable of type Buffer, they'd be able to pass a mutable
-- buffer to concurrent threads. That's why API below is carefully
-- designed to prevent such possibility: clients always work with linear
-- functions Buffer ⊸ Buffer instead and run them on an
-- empty Buffer to extract results.
--
-- In terms of linear-base Buffer is
-- Consumable (see consumeBuffer) and
-- Dupable (see dupBuffer), but not
-- Movable.
--
-- -- >>> :set -XOverloadedStrings -XLinearTypes -- -- >>> import Data.Text.Builder.Linear.Buffer -- -- >>> runBuffer (\b -> '!' .<| "foo" <| (b |> "bar" |>. '.')) -- "!foobar." ---- -- Remember: this is a strict builder, so on contrary to -- Data.Text.Lazy.Builder for optimal performance you should use -- strict left folds instead of lazy right ones. -- -- Buffer is an unlifted datatype, so you can put it into an -- unboxed tuple (# ..., ... #), but not into (..., -- ...). data Buffer :: TYPE ('BoxedRep 'Unlifted) -- | Run a linear function on an empty Buffer, producing a strict -- Text. -- -- Be careful to write runBuffer (\b -> ...) instead of -- runBuffer $ \b -> ..., because current implementation of -- linear types lacks special support for ($). Another option is -- to enable {-# LANGUAGE BlockArguments #-} and write -- runBuffer \b -> .... Alternatively, you can import -- ($) from linear-base. -- -- runBuffer is similar in spirit to mutable arrays API in -- Data.Array.Mutable.Linear, which provides functions -- like fromList ∷ [a] → (Vector -- a ⊸ Ur b) ⊸ Ur b. -- Here the initial buffer is always empty and b is Text. -- Since Text is Movable, Text and -- Ur Text are equivalent. runBuffer :: (Buffer %1 -> Buffer) %1 -> Text -- | Same as runBuffer, but returning a UTF-8 encoded strict -- ByteString. runBufferBS :: (Buffer %1 -> Buffer) %1 -> ByteString -- | Duplicate builder. Feel free to process results in parallel threads. -- Similar to Dupable from linear-base. -- -- It is a bit tricky to use because of current limitations of -- linear types with regards to let and where. E. g., -- one cannot write -- --
-- let (# b1, b2 #) = dupBuffer b in ("foo" <| b1) >< (b2 |> "bar")
--
--
-- Instead write:
--
--
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> runBuffer (\b -> case dupBuffer b of (# b1, b2 #) -> ("foo" <| b1) >< (b2 |> "bar"))
-- "foobar"
--
--
-- Note the unboxed tuple: Buffer is an unlifted datatype, so it
-- cannot be put into (..., ...).
dupBuffer :: Buffer %1 -> (# Buffer, Buffer #)
-- | Consume buffer linearly, similar to Consumable from
-- linear-base.
consumeBuffer :: Buffer %1 -> ()
-- | Erase buffer's content, replacing it with an empty Text.
eraseBuffer :: Buffer %1 -> Buffer
-- | This is just a normal foldl', but with a linear arrow and
-- unlifted accumulator.
foldlIntoBuffer :: forall a. (Buffer %1 -> a -> Buffer) -> Buffer %1 -> [a] -> Buffer
-- | Create an empty Buffer.
--
-- The first Buffer is the input and the second is a new empty
-- Buffer.
--
-- This function is needed in some situations, e.g. with
-- justifyRight. The following example creates a utility function
-- that justify a text and then append it to a buffer.
--
--
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> import Data.Text (Text)
--
-- >>> :{
-- appendJustified :: Buffer %1 -> Text -> Buffer
-- appendJustified b t = case newEmptyBuffer b of
-- -- Note that we need to create a new buffer from the text, in order
-- -- to justify only the text and not the input buffer.
-- (# b', empty #) -> b' >< justifyRight 12 ' ' (empty |> t)
-- :}
--
--
-- -- >>> runBuffer (\b -> (b |> "Test:") `appendJustified` "foo" `appendJustified` "bar") -- "Test: foo bar" ---- -- Note: a previous buffer is necessary in order to create an empty -- buffer with the same characteristics. newEmptyBuffer :: Buffer %1 -> (# Buffer, Buffer #) -- | Concatenate two Buffers, potentially mutating both of them. -- -- You likely need to use dupBuffer to get hold on two builders at -- once: -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> runBuffer (\b -> case dupBuffer b of (# b1, b2 #) -> ("foo" <| b1) >< (b2 |> "bar"))
-- "foobar"
--
(><) :: Buffer %1 -> Buffer %1 -> Buffer
infix 6 ><
-- | Append Char to a Buffer by mutating it.
--
-- -- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> b |>. 'q' |>. 'w') -- "qw" ---- -- Warning: In contrast to singleton, it is the -- responsibility of the caller to sanitize surrogate code points with -- safe. (|>.) :: Buffer %1 -> Char -> Buffer infixl 6 |>. -- | Prepend Char to a Buffer by mutating it. -- --
-- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> 'q' .<| 'w' .<| b) -- "qw" ---- -- Warning: In contrast to singleton, it is the -- responsibility of the caller to sanitize surrogate code points with -- safe. (.<|) :: Char -> Buffer %1 -> Buffer infixr 6 .<| -- | Prepend a given count of a Char to a Buffer. -- --
-- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> prependChars 3 'x' (b |>. 'A')) -- "xxxA" --prependChars :: Word -> Char -> Buffer %1 -> Buffer -- | Apppend a given count of a Char to a Buffer. -- --
-- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> appendChars 3 'x' (b |>. 'A')) -- "Axxx" --appendChars :: Word -> Char -> Buffer %1 -> Buffer -- | Append Text suffix to a Buffer by mutating it. If a -- suffix is statically known, consider using (|>#) for optimal -- performance. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -- -- >>> runBuffer (\b -> b |> "foo" |> "bar") -- "foobar" --(|>) :: Buffer %1 -> Text -> Buffer infixl 6 |> -- | Prepend Text prefix to a Buffer by mutating it. If a -- prefix is statically known, consider using (#<|) for optimal -- performance. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -- -- >>> runBuffer (\b -> "foo" <| "bar" <| b) -- "foobar" --(<|) :: Text -> Buffer %1 -> Buffer infixr 6 <| -- | Append given number of spaces. (|>…) :: Buffer %1 -> Word -> Buffer infixr 6 |>… -- | Prepend given number of spaces. (…<|) :: Word -> Buffer %1 -> Buffer infixr 6 …<| -- | Append a null-terminated UTF-8 string to a Buffer by mutating -- it. E. g., -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -XMagicHash -- -- >>> runBuffer (\b -> b |># "foo"# |># "bar"#) -- "foobar" ---- -- The literal string must not contain zero bytes \0 and must be -- a valid UTF-8, these conditions are not checked. (|>#) :: Buffer %1 -> Addr# -> Buffer infixl 6 |># -- | Prepend a null-terminated UTF-8 string to a Buffer by mutating -- it. E. g., -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -XMagicHash -- -- >>> runBuffer (\b -> "foo"# #<| "bar"# #<| b) -- "foobar" ---- -- The literal string must not contain zero bytes \0 and must be -- a valid UTF-8, these conditions are not checked. -- -- Note: When the syntactic extensions UnboxedTuples or -- UnboxedSums are enabled, extra spaces are required when using -- parentheses: i.e. use ( #<| ) instead of -- (#<|). See the GHC User Guide chapter “[Unboxed -- types and primitive -- operations](https:/downloads.haskell.orgghclatestdocsusers_guideexts/primitives.html#unboxed-tuples)” -- for further information. (#<|) :: Addr# -> Buffer %1 -> Buffer infixr 6 #<| -- | Alias for (#<|). -- | Deprecated: Use (#<|) instead (<|#) :: Addr# -> Buffer %1 -> Buffer infixr 6 <|# -- | Pad a builder from the right side to the specified length with -- the specified character. -- --
-- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> justifyLeft 10 'x' (appendChars 3 'A' b)) -- "AAAxxxxxxx" -- -- >>> runBuffer (\b -> justifyLeft 5 'x' (appendChars 6 'A' b)) -- "AAAAAA" ---- -- Note that newEmptyBuffer is needed in some situations. See -- justifyRight for an example. justifyLeft :: Word -> Char -> Buffer %1 -> Buffer -- | Pad a builder from the left side to the specified length with -- the specified character. -- --
-- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> justifyRight 10 'x' (appendChars 3 'A' b)) -- "xxxxxxxAAA" -- -- >>> runBuffer (\b -> justifyRight 5 'x' (appendChars 6 'A' b)) -- "AAAAAA" ---- -- Note that newEmptyBuffer is needed in some situations. The -- following example creates a utility function that justify a text and -- then append it to a buffer. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -XUnboxedTuples
--
-- >>> import Data.Text.Builder.Linear.Buffer
--
-- >>> import Data.Text (Text)
--
-- >>> :{
-- appendJustified :: Buffer %1 -> Text -> Buffer
-- appendJustified b t = case newEmptyBuffer b of
-- -- Note that we need to create a new buffer from the text, in order
-- -- to justify only the text and not the input buffer.
-- (# b', empty #) -> b' >< justifyRight 12 ' ' (empty |> t)
-- :}
--
--
-- -- >>> runBuffer (\b -> (b |> "Test:") `appendJustified` "foo" `appendJustified` "bar") -- "Test: foo bar" --justifyRight :: Word -> Char -> Buffer %1 -> Buffer -- | Center a builder to the specified length with the specified character. -- --
-- >>> :set -XLinearTypes -- -- >>> runBuffer (\b -> center 10 'x' (appendChars 3 'A' b)) -- "xxxxAAAxxx" -- -- >>> runBuffer (\b -> center 5 'x' (appendChars 6 'A' b)) -- "AAAAAA" ---- -- Note that newEmptyBuffer is needed in some situations. See -- justifyRight for an example. center :: Word -> Char -> Buffer %1 -> Buffer -- | Append decimal number. (|>$) :: (Integral a, FiniteBits a) => Buffer %1 -> a -> Buffer infixl 6 |>$ -- | Prepend decimal number. ($<|) :: (Integral a, FiniteBits a) => a -> Buffer %1 -> Buffer infixr 6 $<| -- | Append the lower-case hexadecimal represensation of a number. -- -- Negative numbers are interpreted as their corresponding unsigned -- number, e.g. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -- -- >>> import Data.Int (Int8, Int16) -- -- >>> runBuffer (\b -> b |>& (-1 :: Int8)) == "ff" -- True -- -- >>> runBuffer (\b -> b |>& (-1 :: Int16)) == "ffff" -- True --(|>&) :: (Integral a, FiniteBits a) => Buffer %1 -> a -> Buffer infixl 6 |>& -- | Prepend the lower-case hexadecimal representation of a number. -- -- Negative numbers are interpreted as their corresponding unsigned -- number, e.g. -- --
-- >>> :set -XOverloadedStrings -XLinearTypes -- -- >>> import Data.Int (Int8, Int16) -- -- >>> runBuffer (\b -> (-1 :: Int8) &<| b) == "ff" -- True -- -- >>> runBuffer (\b -> (-1 :: Int16) &<| b) == "ffff" -- True --(&<|) :: (Integral a, FiniteBits a) => a -> Buffer %1 -> Buffer infixr 6 &<| -- | Append double. (|>%) :: Buffer %1 -> Double -> Buffer infixl 6 |>% -- | Prepend double. (%<|) :: Double -> Buffer %1 -> Buffer infixr 6 %<| -- | Builder for strict Text and ByteString, based on linear -- types. It consistently outperforms Data.Text.Lazy.Builder from -- text as well as a strict builder from text-builder, -- and scales better. module Data.Text.Builder.Linear -- | Thin wrapper over Buffer with a handy Semigroup -- instance. -- --
-- >>> :set -XOverloadedStrings -XMagicHash -- -- >>> fromText "foo" <> fromChar '_' <> fromAddr "bar"# -- "foo_bar" ---- -- Remember: this is a strict builder, so on contrary to -- Data.Text.Lazy.Builder for optimal performance you should use -- strict left folds instead of lazy right ones. -- -- Note that (similar to other builders) concatenation of Builders -- allocates thunks. This is to a certain extent mitigated by aggressive -- inlining, but it is faster to use Buffer directly. newtype Builder Builder :: (Buffer %1 -> Buffer) -> Builder [unBuilder] :: Builder -> Buffer %1 -> Buffer -- | Run Builder computation on an empty Buffer, returning -- strict Text. -- --
-- >>> :set -XOverloadedStrings -XMagicHash -- -- >>> runBuilder (fromText "foo" <> fromChar '_' <> fromAddr "bar"#) -- "foo_bar" ---- -- This function has a polymorphic arrow and thus can be used both in -- usual and linear contexts. runBuilder :: forall m. Builder %m -> Text -- | Same as runBuilder, but returning a UTF-8 encoded strict -- ByteString. runBuilderBS :: forall m. Builder %m -> ByteString -- | Create Builder, containing a given Text. -- --
-- >>> :set -XOverloadedStrings -- -- >>> fromText "foo" <> fromText "bar" -- "foobar" --fromText :: Text -> Builder -- | Create Builder, containing a given Char. -- --
-- >>> fromChar 'x' <> fromChar 'y' -- "xy" ---- -- In contrast to singleton, it's a responsibility of the caller -- to sanitize surrogate code points with safe. fromChar :: Char -> Builder -- | Create Builder, containing a null-terminated UTF-8 string, -- specified by Addr#. -- --
-- >>> :set -XMagicHash -- -- >>> fromAddr "foo"# <> fromAddr "bar"# -- "foobar" ---- -- The literal string must not contain zero bytes \0 and must be -- a valid UTF-8, these conditions are not checked. fromAddr :: Addr# -> Builder -- | Create Builder, containing decimal representation of a given -- integer. -- --
-- >>> fromChar 'x' <> fromDec (123 :: Int) -- "x123" --fromDec :: (Integral a, FiniteBits a) => a -> Builder -- | Create Builder, containing hexadecimal representation of a -- given integer. -- --
-- >>> :set -XMagicHash -- -- >>> fromAddr "0x"# <> fromHex (0x123def :: Int) -- "0x123def" --fromHex :: (Integral a, FiniteBits a) => a -> Builder -- | Create Builder, containing decimal representation of a given -- Double. -- --
-- >>> :set -XMagicHash -- -- >>> fromAddr "pi="# <> fromDouble pi -- "pi=3.141592653589793" --fromDouble :: Double -> Builder instance GHC.Show.Show Data.Text.Builder.Linear.Builder instance GHC.Base.Semigroup Data.Text.Builder.Linear.Builder instance GHC.Base.Monoid Data.Text.Builder.Linear.Builder instance Data.String.IsString Data.Text.Builder.Linear.Builder