packages feed

bytezap-1.0.0: src/Bytezap/Poke/Json.hs

module Bytezap.Poke.Json where

import Data.Word
import Data.Text.Internal qualified as T
import Data.Text.Array qualified as A

import Bytezap.Poke.Derived ( unsafePokeIndexed )
import Bytezap.Poke

import GHC.Exts
import Foreign.C.Types ( CChar )
import GHC.Word

escapedLength8 :: T.Text -> Int
escapedLength8 (T.Text arr off len) = go off 0
  where
    go !i escLen
      | i >= iend = escLen
      | otherwise = go (i+1) (i + escapeW8 (A.unsafeIndex arr i))
    iend = off + len

-- my benchmarks go much faster without INLINE :/
escapeW8 :: Word8 -> Int
escapeW8 w | w >= 0x80 = 1 -- all multibyte chars are unescaped
           | otherwise = case w of 0x5C -> 2 -- \
                                   0x22 -> 2 -- "
                                   0x0A -> 2 -- \n
                                   0x0D -> 2 -- \r
                                   0x09 -> 2 -- \t
                                   _    -> if w < 0x20 then 6 else 1

pokeEscapedTextUnquoted :: T.Text -> Poke s
pokeEscapedTextUnquoted (T.Text arr off len) =
    unsafePokeIndexed (pokeEscapeW8 . A.unsafeIndex arr) off len

-- think we have to poke bytes here still thanks to endianness >:(
pokeEscapeW8 :: Word8 -> Poke s
pokeEscapeW8 w
  | w >= 0x80 = w8 w -- all multibyte chars are unescaped
  | otherwise =
        case w of
          0x5C -> w8 0x5C <> w8 0x5C -- \
          0x22 -> w8 0x5C <> w8 0x22 -- "
          0x0A -> w8 0x5C <> w8 0x6E -- \n
          0x0D -> w8 0x5C <> w8 0x72 -- \r
          0x09 -> w8 0x5C <> w8 0x74 -- \t
          _    ->
            if w >= 0x20 then w8 w else w8 0x5C <> w8 0x75 <> w8 0x30 <> w8 0x30 <> w8AsciiHex w
  where w8 = prim @Word8

-- note I index because I _think_ this is immutable mem! but I might be wrong
-- and very stupid!!
-- look I'm copying some very weird code from bytestring here. idk
w8AsciiHex :: Word8 -> Poke s
w8AsciiHex w = prim (W16# (indexWord16OffAddr# c_lower_hex_table# wI))
  where
    !(I# wI) = fromIntegral w
    !(Ptr c_lower_hex_table#) = c_lower_hex_table

-- TODO lol I'm saying safe b/c I think it's immutable mem. but I might be
-- making a huge fucky wucky here xd
-- can't do Addr# here, no unlifted top-level values x)
foreign import ccall safe "&hs_bytestring_lower_hex_table"
    c_lower_hex_table :: Ptr CChar