module Bytezap.Poke.Derived where

import Bytezap.Poke

import Data.ByteString.Short qualified as SBS
import Data.Text.Internal qualified as T
--import Data.Array.Byte qualified as A
-- ^ text-2.1 and above
import Data.Text.Array qualified as A
import Data.Word
import GHC.Int
import Data.Char ( ord )
import Data.Bits ( shiftR, (.&.) )
import GHC.Exts ( sizeofByteArray# )

-- | Poke a 'SBS.ShortByteString'.
shortByteString :: SBS.ShortByteString -> Poke s
shortByteString :: forall s. ShortByteString -> Poke s
shortByteString (SBS.SBS ByteArray#
ba#) = ByteArray# -> Int# -> Int# -> Poke s
forall s. ByteArray# -> Int# -> Int# -> Poke s
byteArray# ByteArray#
ba# Int#
0# (ByteArray# -> Int#
sizeofByteArray# ByteArray#
ba#)

-- | Poke a 'T.Text'.
text :: T.Text -> Poke s
text :: forall s. Text -> Poke s
text (T.Text (A.ByteArray ByteArray#
ba#) (I# Int#
os#) (I# Int#
len#)) = ByteArray# -> Int# -> Int# -> Poke s
forall s. ByteArray# -> Int# -> Int# -> Poke s
byteArray# ByteArray#
ba# Int#
os# Int#
len#

-- | Poke a 'Char'.
--
-- Adapted from utf8-string.
char :: Char -> Poke s
char :: forall s. Char -> Poke s
char = Int -> Poke s
forall {a} {s}. (Integral a, Bits a) => a -> Poke s
go (Int -> Poke s) -> (Char -> Int) -> Char -> Poke s
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Char -> Int
ord
 where
  w8 :: Word8 -> Poke s
  w8 :: forall s. Word8 -> Poke s
w8 = Word8 -> Poke s
forall a s. Prim' a => a -> Poke s
prim
  go :: a -> Poke s
go a
oc
   | a
oc a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0x7f       = Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (Word8 -> Poke s) -> Word8 -> Poke s
forall a b. (a -> b) -> a -> b
$ a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral a
oc

   | a
oc a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0x7ff      =    Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0xc0 a -> a -> a
forall a. Num a => a -> a -> a
+ (a
oc a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
6)))
                        Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x80 a -> a -> a
forall a. Num a => a -> a -> a
+ a
oc a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x3f))

   | a
oc a -> a -> Bool
forall a. Ord a => a -> a -> Bool
<= a
0xffff     =    Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0xe0 a -> a -> a
forall a. Num a => a -> a -> a
+ (a
oc a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
12)))
                        Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x80 a -> a -> a
forall a. Num a => a -> a -> a
+ ((a
oc a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
6) a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x3f)))
                        Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x80 a -> a -> a
forall a. Num a => a -> a -> a
+ a
oc a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x3f))
   | Bool
otherwise        =    Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0xf0 a -> a -> a
forall a. Num a => a -> a -> a
+ (a
oc a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
18)))
                        Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x80 a -> a -> a
forall a. Num a => a -> a -> a
+ ((a
oc a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
12) a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x3f)))
                        Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x80 a -> a -> a
forall a. Num a => a -> a -> a
+ ((a
oc a -> Int -> a
forall a. Bits a => a -> Int -> a
`shiftR` Int
6) a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x3f)))
                        Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Word8 -> Poke s
forall s. Word8 -> Poke s
w8 (a -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (a
0x80 a -> a -> a
forall a. Num a => a -> a -> a
+ a
oc a -> a -> a
forall a. Bits a => a -> a -> a
.&. a
0x3f))

-- v TODO maybe not needed any more thanks to removing Pokeable class
-- | @unsafePokeIndexed pokeAt off n@ performs @n@ indexed pokes starting from
--   @off@.
--
-- Does not check bounds. Largely intended for bytewise pokes where some work
-- needs to be performed for each byte (e.g. escaping text and poking inline).
unsafePokeIndexed :: (Int -> Poke s) -> Int -> Int -> Poke s
-- no tail recursive option since it'd require binding a ptr, which we can't do
-- due to TYPE rr.
-- if you simply expand the monoidal ops here, you get the tail call ver. but
-- like, will GHC be able to do that?
-- hoping INLINE is good enough. but maybe need to check strictness.
unsafePokeIndexed :: forall s. (Int -> Poke s) -> Int -> Int -> Poke s
unsafePokeIndexed Int -> Poke s
pokeAt Int
off Int
n = Int -> Poke s
go Int
off
  where
    go :: Int -> Poke s
go Int
i | Int
i Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
>= Int
iend = Poke s
forall a. Monoid a => a
mempty
         | Bool
otherwise = Int -> Poke s
pokeAt Int
i Poke s -> Poke s -> Poke s
forall a. Semigroup a => a -> a -> a
<> Int -> Poke s
go (Int
iInt -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)
    iend :: Int
iend = Int
off Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
n