{-# language BangPatterns #-}
{-# language BinaryLiterals #-}
{-# language DataKinds #-}
{-# language DeriveFunctor #-}
{-# language DerivingStrategies #-}
{-# language DuplicateRecordFields #-}
{-# language GADTSyntax #-}
{-# language KindSignatures #-}
{-# language LambdaCase #-}
{-# language MagicHash #-}
{-# language MultiWayIf #-}
{-# language NamedFieldPuns #-}
{-# language PolyKinds #-}
{-# language RankNTypes #-}
{-# language ScopedTypeVariables #-}
{-# language StandaloneDeriving #-}
{-# language TypeApplications #-}
{-# language UnboxedSums #-}
{-# language UnboxedTuples #-}

-- | Everything in this module is unsafe and can lead to
-- nondeterministic output or segfaults if used incorrectly.
module Data.Bytes.Parser.Unsafe
  ( -- * Types
    Parser(..)
    -- * Functions
  , cursor
  , cursor#
  , expose
  , unconsume
  , jump
  , uneffectful
  ) where

import Prelude hiding (length)

import Data.Bytes.Parser.Internal (Parser(..),uneffectful,uneffectfulInt#)
import Data.Bytes.Parser.Internal (Result(..))
import Data.Bytes.Types (Bytes(..))
import Data.Primitive (ByteArray)
import GHC.Exts (Int#,Int(I#))


-- | Get the current offset into the chunk. Using this makes
-- it possible to observe the internal difference between 'Bytes'
-- that refer to equivalent slices. Be careful.
cursor :: Parser e s Int
cursor :: forall e s. Parser e s Int
cursor = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \Bytes{Int
$sel:offset:Bytes :: Bytes -> Int
offset :: Int
offset,Int
$sel:length:Bytes :: Bytes -> Int
length :: Int
length} ->
  forall e a. a -> Int -> Int -> Result e a
Success Int
offset Int
offset Int
length

-- | Variant of 'cursor' with unboxed result.
cursor# :: Parser e s Int#
cursor# :: forall e s. Parser e s Int#
cursor# = forall e s. (Bytes -> Result# e Int#) -> Parser e s Int#
uneffectfulInt# forall a b. (a -> b) -> a -> b
$ \Bytes{$sel:offset:Bytes :: Bytes -> Int
offset=I# Int#
off,$sel:length:Bytes :: Bytes -> Int
length=I# Int#
len} -> (# | (# Int#
off, Int#
off, Int#
len #) #)

-- | Return the byte array being parsed. This includes bytes
-- that preceed the current offset and may include bytes that
-- go beyond the length. This is somewhat dangerous, so only
-- use this is you know what you're doing.
expose :: Parser e s ByteArray
expose :: forall e s. Parser e s ByteArray
expose = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \Bytes{Int
length :: Int
$sel:length:Bytes :: Bytes -> Int
length,Int
offset :: Int
$sel:offset:Bytes :: Bytes -> Int
offset,ByteArray
$sel:array:Bytes :: Bytes -> ByteArray
array :: ByteArray
array} ->
  forall e a. a -> Int -> Int -> Result e a
Success ByteArray
array Int
offset Int
length

-- | Move the cursor back by @n@ bytes. Precondition: you
-- must have previously consumed at least @n@ bytes.
unconsume :: Int -> Parser e s ()
unconsume :: forall e s. Int -> Parser e s ()
unconsume Int
n = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \Bytes{Int
length :: Int
$sel:length:Bytes :: Bytes -> Int
length,Int
offset :: Int
$sel:offset:Bytes :: Bytes -> Int
offset} ->
  forall e a. a -> Int -> Int -> Result e a
Success () (Int
offset forall a. Num a => a -> a -> a
- Int
n) (Int
length forall a. Num a => a -> a -> a
+ Int
n)

-- | Set the position to the given index. Precondition: the index
-- must be valid. It should be the result of an earlier call to
-- 'cursor'.
jump :: Int -> Parser e s ()
jump :: forall e s. Int -> Parser e s ()
jump Int
ix = forall e a s. (Bytes -> Result e a) -> Parser e s a
uneffectful forall a b. (a -> b) -> a -> b
$ \(Bytes{Int
length :: Int
$sel:length:Bytes :: Bytes -> Int
length,Int
offset :: Int
$sel:offset:Bytes :: Bytes -> Int
offset}) ->
  forall e a. a -> Int -> Int -> Result e a
Success () Int
ix (Int
length forall a. Num a => a -> a -> a
+ (Int
offset forall a. Num a => a -> a -> a
- Int
ix))