{-
  Copyright 2016 Awake Networks

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.
-}

-- | This module extends the "Data.ByteString.Builder" module by memoizing the
-- resulting length of each `Builder`
--
-- Example use:
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word32BE 42 <> charUtf8 'λ'))
-- [0,0,0,42,206,187]

{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Proto3.Wire.Builder
    {-# DEPRECATED "This module is no longer used by the rest of the proto3-wire package." #-}
    (
      -- * `Builder` type
      Builder

      -- * Create `Builder`s
    , byteString
    , lazyByteString
    , shortByteString
    , word8
    , word16BE
    , word16LE
    , word32BE
    , word32LE
    , word64BE
    , word64LE
    , word64Base128LEVar
    , int8
    , int16BE
    , int16LE
    , int32BE
    , int32LE
    , int64BE
    , int64LE
    , floatBE
    , floatLE
    , doubleBE
    , doubleLE
    , char7
    , string7
    , char8
    , string8
    , charUtf8
    , stringUtf8

      -- * Consume `Builder`s
    , builderLength
    , rawBuilder
    , toLazyByteString
    , hPutBuilder

    -- * Internal API
    , unsafeMakeBuilder
    ) where

import           Data.Bits                     ((.|.), shiftR)
import qualified Data.ByteString               as B
import qualified Data.ByteString.Builder       as BB
import qualified Data.ByteString.Builder.Extra as BB
import qualified Data.ByteString.Lazy          as BL
import qualified Data.ByteString.Short         as BS
import           Data.Char                     ( ord )
import           Data.Int                      ( Int8, Int16, Int32, Int64 )
import           Data.Semigroup                ( Sum(..) )
import           Data.Word                     ( Word8, Word16, Word32, Word64 )
import           System.IO                     ( Handle )

-- $setup
-- >>> :set -XOverloadedStrings -Wno-warnings-deprecations
-- >>> :module Proto3.Wire.Builder

-- | A `Builder` is like a @"Data.ByteString.Builder".`BB.Builder`@, but also
-- memoizes the resulting length so that we can efficiently encode nested
-- embedded messages.
--
-- You create a `Builder` by using one of the primitives provided in the
-- \"Create `Builder`s\" section.
--
-- You combine `Builder`s using the `Monoid` and `Semigroup` instances.
--
-- You consume a `Builder` by using one of the utilities provided in the
-- \"Consume `Builder`s\" section.
data Builder = Builder {-# UNPACK #-} !(Sum Word) BB.Builder

instance Semigroup Builder where
  Builder Sum Word
s Builder
b <> :: Builder -> Builder -> Builder
<> Builder Sum Word
s1 Builder
b1 = Sum Word -> Builder -> Builder
Builder (Sum Word
s Sum Word -> Sum Word -> Sum Word
forall a. Semigroup a => a -> a -> a
<> Sum Word
s1) (Builder
b Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<> Builder
b1)

instance Monoid Builder where
  mempty :: Builder
mempty = Sum Word -> Builder -> Builder
Builder Sum Word
forall a. Monoid a => a
mempty Builder
forall a. Monoid a => a
mempty
  mappend :: Builder -> Builder -> Builder
mappend = Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
(<>)

instance Show Builder where
  showsPrec :: Int -> Builder -> ShowS
showsPrec Int
prec Builder
builder =
      Bool -> ShowS -> ShowS
showParen (Int
prec Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
> Int
10)
        (String -> ShowS
showString String
"Proto3.Wire.Builder.lazyByteString " ShowS -> ShowS -> ShowS
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ByteString -> ShowS
forall a. Show a => a -> ShowS
shows ByteString
bytes)
    where
      bytes :: ByteString
bytes = Builder -> ByteString
toLazyByteString Builder
builder

-- | Retrieve the length of a `Builder`
--
-- > builderLength (x <> y) = builderLength x + builderLength y
-- >
-- > builderLength mempty = 0
--
-- >>> builderLength (word32BE 42)
-- 4
-- >>> builderLength (stringUtf8 "ABC")
-- 3
builderLength :: Builder -> Word
builderLength :: Builder -> Word
builderLength (Builder Sum Word
x Builder
_) = Sum Word -> Word
forall a. Sum a -> a
getSum Sum Word
x

-- | Retrieve the underlying @"Data.ByteString.Builder".`BB.Builder`@
--
-- > rawBuilder (x <> y) = rawBuilder x <> rawBuilder y
-- >
-- > rawBuilder mempty = mempty
--
-- >>> Data.ByteString.Builder.toLazyByteString (rawBuilder (stringUtf8 "ABC"))
-- "ABC"
rawBuilder :: Builder -> BB.Builder
rawBuilder :: Builder -> Builder
rawBuilder (Builder Sum Word
_ Builder
x) = Builder
x

-- | Create a `Builder` from a @"Data.ByteString.Builder".`BB.Builder`@ and a
-- length.  This is unsafe because you are responsible for ensuring that the
-- provided length value matches the length of the
-- @"Data.ByteString.Builder".`BB.Builder`@
--
-- >>> unsafeMakeBuilder 3 (Data.ByteString.Builder.stringUtf8 "ABC")
-- Proto3.Wire.Builder.lazyByteString "ABC"
unsafeMakeBuilder :: Word -> BB.Builder -> Builder
unsafeMakeBuilder :: Word -> Builder -> Builder
unsafeMakeBuilder Word
len Builder
bldr = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
len) Builder
bldr

-- | Create a lazy `BL.ByteString` from a `Builder`
--
-- > toLazyByteString (x <> y) = toLazyByteString x <> toLazyByteString y
-- >
-- > toLazyByteString mempty = mempty
--
-- >>> toLazyByteString (stringUtf8 "ABC")
-- "ABC"
toLazyByteString :: Builder -> BL.ByteString
toLazyByteString :: Builder -> ByteString
toLazyByteString (Builder (Sum Word
len) Builder
bb) =
    AllocationStrategy -> ByteString -> Builder -> ByteString
BB.toLazyByteStringWith AllocationStrategy
strat ByteString
BL.empty Builder
bb
  where
    -- If the supplied length is accurate then we will perform just
    -- one allocation.  An inaccurate length would indicate a bug
    -- in one of the primitives that produces a 'Builder'.
    strat :: AllocationStrategy
strat = Int -> Int -> AllocationStrategy
BB.safeStrategy (Word -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word
len) Int
BB.defaultChunkSize
{-# NOINLINE toLazyByteString #-}
  -- NOINLINE to avoid bloating caller; see docs for 'BB.toLazyByteStringWith'.

-- | Write a `Builder` to a `Handle`
--
-- > hPutBuilder handle (x <> y) = hPutBuilder handle x <> hPutBuilder handle y
-- >
-- > hPutBuilder handle mempty = mempty
--
-- >>> hPutBuilder System.IO.stdout (stringUtf8 "ABC\n")
-- ABC
hPutBuilder :: Handle -> Builder -> IO ()
hPutBuilder :: Handle -> Builder -> IO ()
hPutBuilder Handle
handle = Handle -> Builder -> IO ()
BB.hPutBuilder Handle
handle (Builder -> IO ()) -> (Builder -> Builder) -> Builder -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Builder -> Builder
rawBuilder

-- | Convert a strict `B.ByteString` to a `Builder`
--
-- > byteString (x <> y) = byteString x <> byteString y
-- >
-- > byteString mempty = mempty
--
-- >>> byteString "ABC"
-- Proto3.Wire.Builder.lazyByteString "ABC"
byteString :: B.ByteString -> Builder
byteString :: ByteString -> Builder
byteString ByteString
bs =
  Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int
B.length ByteString
bs))) (ByteString -> Builder
BB.byteStringCopy ByteString
bs)
    -- NOTE: We want 'toLazyByteString' to produce a single chunk (unless
    -- incorrect uses of 'unsafeMakeBuilder' sabotage the length prediction).
    --
    -- To that end, 'toLazyByteString' allocates a first chunk of exactly the
    -- builder length.  That length should be accurate unless there is a bug,
    -- either within this library or in some arguments to 'unsafeMakeBuilder'.
    --
    -- If the given 'bs :: B.ByteString' is longer than a certain threshold,
    -- then passing it to 'BB.byteString' would produce a builder that closes
    -- the current chunk and appends 'bs' as its own chunk, without copying.
    -- That would waste some of the chunk allocated by 'toLazyByteString'.
    --
    -- Therefore we force copying of 'bs' by using 'BB.byteStringCopy' here.

-- | Convert a lazy `BL.ByteString` to a `Builder`
--
-- Warning: evaluating the length will force the lazy `BL.ByteString`'s chunks,
-- and they will remain allocated until you finish using the builder.
--
-- > lazyByteString (x <> y) = lazyByteString x <> lazyByteString y
-- >
-- > lazyByteString mempty = mempty
--
-- > lazyByteString . toLazyByteString = id
-- >
-- > toLazyByteString . lazyByteString = id
--
-- >>> lazyByteString "ABC"
-- Proto3.Wire.Builder.lazyByteString "ABC"
lazyByteString :: BL.ByteString -> Builder
lazyByteString :: ByteString -> Builder
lazyByteString ByteString
bl =
  Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Int64 -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ByteString -> Int64
BL.length ByteString
bl))) (ByteString -> Builder
BB.lazyByteStringCopy ByteString
bl)
    -- NOTE: We use 'BB.lazyByteStringCopy' here for the same reason
    -- that 'byteString' uses 'BB.byteStringCopy'.  For the rationale,
    -- please see the comments in the implementation of 'byteString'.

-- | Convert a `BS.ShortByteString` to a `Builder`
--
-- > shortByteString (x <> y) = shortByteString x <> shortByteString y
-- >
-- > shortByteString mempty = mempty
--
-- >>> shortByteString "ABC"
-- Proto3.Wire.Builder.lazyByteString "ABC"
shortByteString :: BS.ShortByteString -> Builder
shortByteString :: ShortByteString -> Builder
shortByteString ShortByteString
bs =
  Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (ShortByteString -> Int
BS.length ShortByteString
bs))) (ShortByteString -> Builder
BB.shortByteString ShortByteString
bs)

-- | Convert a `Word8` to a `Builder`
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word8 42))
-- [42]
word8 :: Word8 -> Builder
word8 :: Word8 -> Builder
word8 Word8
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
1) (Word8 -> Builder
BB.word8 Word8
w)

-- | Convert a `Int8` to a `Builder`
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int8 (-5)))
-- [251]
int8 :: Int8 -> Builder
int8 :: Int8 -> Builder
int8 Int8
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
1) (Int8 -> Builder
BB.int8 Int8
w)

-- | Convert a `Word16` to a `Builder` by storing the bytes in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word16BE 42))
-- [0,42]
word16BE :: Word16 -> Builder
word16BE :: Word16 -> Builder
word16BE Word16
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
2) (Word16 -> Builder
BB.word16BE Word16
w)

-- | Convert a `Word16` to a `Builder` by storing the bytes in little-endian
-- order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word16LE 42))
-- [42,0]
word16LE :: Word16 -> Builder
word16LE :: Word16 -> Builder
word16LE Word16
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
2) (Word16 -> Builder
BB.word16LE Word16
w)

-- | Convert an `Int16` to a `Builder` by storing the bytes in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int16BE (-5)))
-- [255,251]
int16BE :: Int16 -> Builder
int16BE :: Int16 -> Builder
int16BE Int16
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
2) (Int16 -> Builder
BB.int16BE Int16
w)

-- | Convert an `Int16` to a `Builder` by storing the bytes in little-endian
-- order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int16LE (-5)))
-- [251,255]
int16LE :: Int16 -> Builder
int16LE :: Int16 -> Builder
int16LE Int16
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
2) (Int16 -> Builder
BB.int16LE Int16
w)

-- | Convert a `Word32` to a `Builder` by storing the bytes in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word32BE 42))
-- [0,0,0,42]
word32BE :: Word32 -> Builder
word32BE :: Word32 -> Builder
word32BE Word32
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Word32 -> Builder
BB.word32BE Word32
w)

-- | Convert a `Word32` to a `Builder` by storing the bytes in little-endian
-- order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word32LE 42))
-- [42,0,0,0]
word32LE :: Word32 -> Builder
word32LE :: Word32 -> Builder
word32LE Word32
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Word32 -> Builder
BB.word32LE Word32
w)

-- | Convert an `Int32` to a `Builder` by storing the bytes in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int32BE (-5)))
-- [255,255,255,251]
int32BE :: Int32 -> Builder
int32BE :: Int32 -> Builder
int32BE Int32
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Int32 -> Builder
BB.int32BE Int32
w)

-- | Convert an `Int32` to a `Builder` by storing the bytes in little-endian
-- order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int32LE (-5)))
-- [251,255,255,255]
int32LE :: Int32 -> Builder
int32LE :: Int32 -> Builder
int32LE Int32
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Int32 -> Builder
BB.int32LE Int32
w)

-- | Convert a `Float` to a `Builder` by storing the bytes in IEEE-754 format in
-- big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (floatBE 4.2))
-- [64,134,102,102]
floatBE :: Float -> Builder
floatBE :: Float -> Builder
floatBE Float
f = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Float -> Builder
BB.floatBE Float
f)

-- | Convert a `Float` to a `Builder` by storing the bytes in IEEE-754 format in
-- little-endian order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (floatLE 4.2))
-- [102,102,134,64]
floatLE :: Float -> Builder
floatLE :: Float -> Builder
floatLE Float
f = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Float -> Builder
BB.floatLE Float
f)

-- | Convert a `Word64` to a `Builder` by storing the bytes in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word64BE 42))
-- [0,0,0,0,0,0,0,42]
word64BE :: Word64 -> Builder
word64BE :: Word64 -> Builder
word64BE Word64
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Word64 -> Builder
BB.word64BE Word64
w)

-- | Convert a `Word64` to a `Builder` by storing the bytes in little-endian
-- order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (word64LE 42))
-- [42,0,0,0,0,0,0,0]
word64LE :: Word64 -> Builder
word64LE :: Word64 -> Builder
word64LE Word64
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Word64 -> Builder
BB.word64LE Word64
w)

-- | Convert a `Word64` to a `Builder` using this variable-length encoding:
--
--   1. Convert the given value to a base 128 representation
--   without unnecessary digits (that is, omit zero digits
--   unless they are less significant than nonzero digits).
--
--   2. Present those base-128 digits in order of increasing
--   significance (that is, in little-endian order).
--
--   3. Add 128 to every digit except the most significant digit,
--   yielding a sequence of octets terminated by one that is <= 127.
--
-- This encoding is used in the wire format of Protocol Buffers version 3.
word64Base128LEVar :: Word64 -> Builder
{-
Prelude Data.Bits Numeric> map (("0x"++) .($"").showHex) $ map bit $ take 11 [0,7..]
["0x1","0x80","0x4000","0x200000","0x10000000","0x800000000","0x40000000000","0x2000000000000","0x100000000000000","0x8000000000000000","0x400000000000000000"]
-}
word64Base128LEVar :: Word64 -> Builder
word64Base128LEVar Word64
i
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x80         = Word8 -> Builder
word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i)
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x4000       = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
2) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x200000     = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
3) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x10000000   = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
4) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x800000000  = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
5) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                          Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
28)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x40000000000      = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
6) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
28) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
35)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x2000000000000    = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
7) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
28) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
35) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
42)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x100000000000000  = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
28) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
35) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
42) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
49)))
    | Word64
i Word64 -> Word64 -> Bool
forall a. Ord a => a -> a -> Bool
< Word64
0x8000000000000000 = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
9) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
28) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
35) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
42) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
49) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
56)))
    | Bool
otherwise              = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
10) (Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word64
i Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
7) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
14) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
21) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
28) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
35) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
42) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
49) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
56) Word8 -> Word8 -> Word8
forall a. Bits a => a -> a -> a
.|. Word8
0x80) Builder -> Builder -> Builder
forall a. Semigroup a => a -> a -> a
<>
                                                 Word8 -> Builder
BB.word8 (Word64 -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Word64
i Word64 -> Int -> Word64
forall a. Bits a => a -> Int -> a
`shiftR` Int
63)))


-- | Convert an `Int64` to a `Builder` by storing the bytes in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int64BE (-5)))
-- [255,255,255,255,255,255,255,251]
int64BE :: Int64 -> Builder
int64BE :: Int64 -> Builder
int64BE Int64
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Int64 -> Builder
BB.int64BE Int64
w)

-- | Convert an `Int64` to a `Builder` by storing the bytes in little-endian
-- order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (int64LE (-5)))
-- [251,255,255,255,255,255,255,255]
int64LE :: Int64 -> Builder
int64LE :: Int64 -> Builder
int64LE Int64
w = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Int64 -> Builder
BB.int64LE Int64
w)

-- | Convert a `Double` to a `Builder` by storing the bytes in IEEE-754 format
-- in big-endian order
--
-- In other words, the most significant byte is stored first and the least
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (doubleBE 4.2))
-- [64,16,204,204,204,204,204,205]
doubleBE :: Double -> Builder
doubleBE :: Double -> Builder
doubleBE Double
f = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Double -> Builder
BB.doubleBE Double
f)

-- | Convert a `Double` to a `Builder` by storing the bytes in IEEE-754 format
-- in little-endian order
--
-- In other words, the least significant byte is stored first and the most
-- significant byte is stored last
--
-- >>> Data.ByteString.Lazy.unpack (toLazyByteString (doubleLE 4.2))
-- [205,204,204,204,204,204,16,64]
doubleLE :: Double -> Builder
doubleLE :: Double -> Builder
doubleLE Double
f = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
8) (Double -> Builder
BB.doubleLE Double
f)

-- | Convert an @ASCII@ `Char` to a `Builder`
--
-- __Careful:__ If you provide a Unicode character that is not part of the
-- @ASCII@ alphabet this will only encode the lowest 7 bits
--
-- >>> char7 ';'
-- Proto3.Wire.Builder.lazyByteString ";"
-- >>> char7 'λ' -- Example of truncation
-- Proto3.Wire.Builder.lazyByteString ";"
char7 :: Char -> Builder
char7 :: Char -> Builder
char7 Char
c = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
1) (Char -> Builder
BB.char7 Char
c)

-- | Convert an @ASCII@ `String` to a `Builder`
--
-- __Careful:__ If you provide a Unicode `String` that has non-@ASCII@
-- characters then this will only encode the lowest 7 bits of each character
--
-- > string7 (x <> y) = string7 x <> string7 y
-- >
-- > string7 mempty = mempty
--
-- >>> string7 "ABC"
-- Proto3.Wire.Builder.lazyByteString "ABC"
-- >>> string7 "←↑→↓" -- Example of truncation
-- Proto3.Wire.Builder.lazyByteString "\DLE\DC1\DC2\DC3"
string7 :: String -> Builder
string7 :: String -> Builder
string7 String
s = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s))) (String -> Builder
BB.string7 String
s)

-- | Convert an @ISO/IEC 8859-1@ `Char` to a `Builder`
--
-- __Careful:__ If you provide a Unicode character that is not part of the
-- @ISO/IEC 8859-1@ alphabet then this will only encode the lowest 8 bits
--
-- >>> char8 ';'
-- Proto3.Wire.Builder.lazyByteString ";"
-- >>> char8 'λ' -- Example of truncation
-- Proto3.Wire.Builder.lazyByteString "\187"
char8 :: Char -> Builder
char8 :: Char -> Builder
char8 Char
c = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum Word
1) (Char -> Builder
BB.char8 Char
c)

-- | Convert an @ISO/IEC 8859-1@ `String` to a `Builder`
--
-- __Careful:__ If you provide a Unicode `String` that has non-@ISO/IEC 8859-1@
-- characters then this will only encode the lowest 8 bits of each character
--
-- > string8 (x <> y) = string8 x <> string8 y
-- >
-- > string8 mempty = mempty
--
-- >>> string8 "ABC"
-- Proto3.Wire.Builder.lazyByteString "ABC"
-- >>> string8 "←↑→↓" -- Example of truncation
-- Proto3.Wire.Builder.lazyByteString "\144\145\146\147"
string8 :: String -> Builder
string8 :: String -> Builder
string8 String
s = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Int -> Word
forall a b. (Integral a, Num b) => a -> b
fromIntegral (String -> Int
forall a. [a] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length String
s))) (String -> Builder
BB.string8 String
s)

-- | Convert a Unicode `Char` to a `Builder` using a @UTF-8@ encoding
--
-- >>> charUtf8 'A'
-- Proto3.Wire.Builder.lazyByteString "A"
-- >>> charUtf8 'λ'
-- Proto3.Wire.Builder.lazyByteString "\206\187"
-- >>> hPutBuilder System.IO.stdout (charUtf8 'λ' <> charUtf8 '\n')
-- λ
charUtf8 :: Char -> Builder
charUtf8 :: Char -> Builder
charUtf8 Char
c = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Char -> Word
utf8Width Char
c)) (Char -> Builder
BB.charUtf8 Char
c)

-- | Convert a Unicode `String` to a `Builder` using a @UTF-8@ encoding
--
-- > stringUtf8 (x <> y) = stringUtf8 x <> stringUtf8 y
-- >
-- > stringUtf8 mempty = mempty
--
-- >>> stringUtf8 "ABC"
-- Proto3.Wire.Builder.lazyByteString "ABC"
-- >>> stringUtf8 "←↑→↓"
-- Proto3.Wire.Builder.lazyByteString "\226\134\144\226\134\145\226\134\146\226\134\147"
-- >>> hPutBuilder System.IO.stdout (stringUtf8 "←↑→↓\n")
-- ←↑→↓
stringUtf8 :: String -> Builder
stringUtf8 :: String -> Builder
stringUtf8 String
s = Sum Word -> Builder -> Builder
Builder (Word -> Sum Word
forall a. a -> Sum a
Sum (Word -> String -> Word
len Word
0 String
s)) (String -> Builder
BB.stringUtf8 String
s)
  where
    len :: Word -> String -> Word
len !Word
n []      = Word
n
    len !Word
n (Char
h : String
t) = Word -> String -> Word
len (Word
n Word -> Word -> Word
forall a. Num a => a -> a -> a
+ Char -> Word
utf8Width Char
h) String
t
{-# INLINABLE stringUtf8 #-}
  -- INLINABLE so that if the input is constant, the
  -- compiler has the opportunity to precompute its length.

utf8Width :: Char -> Word
utf8Width :: Char -> Word
utf8Width Char
c = case Char -> Int
ord Char
c of
  Int
o | Int
o Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0x007F -> Word
1
    | Int
o Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0x07FF -> Word
2
    | Int
o Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
<= Int
0xFFFF -> Word
3
    | Bool
otherwise   -> Word
4
{-# INLINE utf8Width #-}