HORIZON HASKELLDocslts/ghc-9.14.x7a6c33e2026-10-12Search packagesCtrl K
Theme: |

GHC 9.14.1 · lts/ghc-9.14.x · 7a6c33e · 2026-10-12

Moduletext-builder-linear-0.1.4GHC2021

Data.Text.Builder.Linear.Buffer

Buffer for strict Text, based on linear types.

Contents
  1. Type
  2. Basic interface
  3. Single character
  4. Multiple characters
  5. Character replication
  6. Text
  7. Raw Addr#
  8. Padding
  9. Number formatting
  10. Decimal
  11. Bounded numbers
  12. Unbounded numbers
  13. Hexadecimal
  14. Lower-case
  15. Upper-case and padding
  16. Double
Synopsis

Type

datadata Buffer where

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.

Example3 expressions
:set -XOverloadedStrings -XLinearTypesimport Data.Text.Builder.Linear.BufferrunBuffer (\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 (..., ...).

Basic interface

valuerunBuffer :: (Buffer %1 -> Buffer) %1 -> Text

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 ∷ Movable b ⇒ [a] → (Array a ⊸ b) ⊸ b. Here the initial buffer is always empty and b is Text.

valuedupBuffer :: Buffer %1 -> (# Buffer, Buffer #)

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:

Example3 expressions
:set -XOverloadedStrings -XLinearTypes -XUnboxedTuplesimport Data.Text.Builder.Linear.BufferrunBuffer (\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 (..., ...).

valuenewEmptyBuffer :: Buffer %1 -> (# Buffer, 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.

Example4 expressions
:set -XOverloadedStrings -XLinearTypes -XUnboxedTuplesimport Data.Text.Builder.Linear.Bufferimport Data.Text (Text):{appendJustified :: Buffer %1 -> Text -> BufferappendJustified 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):}
Example1 expression
runBuffer (\b -> (b |> "Test:") `appendJustified` "AAA" `appendJustified` "BBBBBBB")"Test:         AAA     BBBBBBB"

Note: a previous buffer is necessary in order to create an empty buffer with the same pinnedness.

value(><) :: Buffer %1 -> 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:

Example3 expressions
:set -XOverloadedStrings -XLinearTypes -XUnboxedTuplesimport Data.Text.Builder.Linear.BufferrunBuffer (\b -> case dupBuffer b of (# b1, b2 #) -> ("foo" <| b1) >< (b2 |> "bar"))"foobar"

Single character

value(|>.) :: Buffer %1 -> Char -> Buffer

Append Char to a Buffer by mutating it.

Example2 expressions
:set -XLinearTypesrunBuffer (\b -> b |>. 'q' |>. 'w')"qw"

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

value(.<|) :: Char -> Buffer %1 -> Buffer

Prepend Char to a Buffer by mutating it.

Example2 expressions
:set -XLinearTypesrunBuffer (\b -> 'q' .<| 'w' .<| b)"qw"

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

Multiple characters

Character replication

valueprependChars :: Word -> Char -> Buffer %1 -> Buffer

Prepend a given count of a Char to a Buffer.

Example2 expressions
:set -XLinearTypesrunBuffer (\b -> prependChars 3 'x' (b |>. 'A'))"xxxA"

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

valueappendChars :: Word -> Char -> Buffer %1 -> Buffer

Apppend a given count of a Char to a Buffer.

Example2 expressions
:set -XLinearTypesrunBuffer (\b -> appendChars 3 'x' (b |>. 'A'))"Axxx"

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

Text

value(|>) :: Buffer %1 -> Text -> Buffer

Append Text suffix to a Buffer by mutating it. If a suffix is statically known, consider using (|>#) for optimal performance.

Example2 expressions
:set -XOverloadedStrings -XLinearTypesrunBuffer (\b -> b |> "foo" |> "bar")"foobar"
value(<|) :: Text -> Buffer %1 -> Buffer

Prepend Text prefix to a Buffer by mutating it. If a prefix is statically known, consider using (#<|) for optimal performance.

Example2 expressions
:set -XOverloadedStrings -XLinearTypesrunBuffer (\b -> "foo" <| "bar" <| b)"foobar"

Raw Addr#

value(|>#) :: Buffer %1 -> Addr# -> Buffer

Append a null-terminated UTF-8 string to a Buffer by mutating it. E. g.,

Example2 expressions
:set -XOverloadedStrings -XLinearTypes -XMagicHashrunBuffer (\b -> b |># "foo"# |># "bar"#)"foobar"

The literal string must not contain zero bytes \NUL and must be a valid UTF-8, these conditions are not checked.

value(#<|) :: Addr# -> Buffer %1 -> Buffer

Prepend a null-terminated UTF-8 string to a Buffer by mutating it. E. g.,

Example2 expressions
:set -XOverloadedStrings -XLinearTypes -XMagicHashrunBuffer (\b -> "foo"# #<| "bar"# #<| b)"foobar"

The literal string must not contain zero bytes \NUL 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” for further information.

Padding

valuejustifyLeft :: Word -> Char -> Buffer %1 -> Buffer

Pad a builder from the right side to the specified length with the specified character.

Example3 expressions
:set -XLinearTypesrunBuffer (\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.

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

valuejustifyRight :: Word -> Char -> Buffer %1 -> Buffer

Pad a builder from the left side to the specified length with the specified character.

Example3 expressions
:set -XLinearTypesrunBuffer (\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.

Example4 expressions
:set -XOverloadedStrings -XLinearTypes -XUnboxedTuplesimport Data.Text.Builder.Linear.Bufferimport Data.Text (Text):{appendJustified :: Buffer %1 -> Text -> BufferappendJustified 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):}
Example1 expression
runBuffer (\b -> (b |> "Test:") `appendJustified` "AAA" `appendJustified` "BBBBBBB")"Test:         AAA     BBBBBBB"

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

valuecenter :: Word -> Char -> Buffer %1 -> Buffer

Center a builder to the specified length with the specified character.

Example3 expressions
:set -XLinearTypesrunBuffer (\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.

Warning: In contrast to singleton, it is the responsibility of the caller to sanitize surrogate code points with safe.

Number formatting

Decimal

Bounded numbers

Unbounded numbers

Hexadecimal

Lower-case

value(|>&) :: (Integral a, FiniteBits a) => Buffer %1 -> a -> Buffer

Append the lower-case hexadecimal representation of a bounded integral number.

Negative numbers are interpreted as their corresponding unsigned number:

Example4 expressions
:set -XOverloadedStrings -XLinearTypesimport Data.Int (Int8, Int16)runBuffer (\b -> b |>& (-1 :: Int8)) == "ff"TruerunBuffer (\b -> b |>& (-1 :: Int16)) == "ffff"True
value(&<|) :: (Integral a, FiniteBits a) => a -> Buffer %1 -> Buffer

Prepend the lower-case hexadecimal representation of a bounded integral number.

Negative numbers are interpreted as their corresponding unsigned number:

Example4 expressions
:set -XOverloadedStrings -XLinearTypesimport Data.Int (Int8, Int16)runBuffer (\b -> (-1 :: Int8) &<| b) == "ff"TruerunBuffer (\b -> (-1 :: Int16) &<| b) == "ffff"True

Upper-case and padding

Note that neither upper case nor padded hexadecimal formatting is provided. This package provides a minimal API with utility functions only for common cases. For other use cases, please adapt the code of this package, e.g. as shown in the Unicode code point example.

Double

value(|>%) :: Buffer %1 -> Double -> Buffer

Append the decimal representation of a Double.

Example1 expression
runBuffer (\b -> b |>% 123.456)"123.456"
Example1 expression
runBuffer (\b -> b |>% 1.23e7)"1.23e7"