{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.Packed.Skippable (Skippable (..), unsafeSkipN) where

import Data.Kind
import Data.Packed.Reader hiding (return)
import Foreign (plusPtr)
import Foreign.Storable

class Skippable a where
    -- A function that moves the cursor at the end of the first packed value in the buffer.
    --
    -- Beware, this does not rely on `Data.Packed.FieldSize`, therefore it usually entails a traversals
    skip :: PackedReader '[a] r ()

instance (Storable a) => Skippable a where
    skip :: forall (r :: [*]). PackedReader '[a] r ()
skip = Int -> PackedReader '[a] r ()
forall (a :: [*]) (r :: [*]). Int -> PackedReader a r ()
unsafeSkipN (a -> Int
forall a. Storable a => a -> Int
sizeOf (a
forall a. HasCallStack => a
undefined :: a))

{-# INLINE unsafeSkipN #-}

-- | UNSAFE: Shifts the cursor to n bytes to the right.
unsafeSkipN :: forall (a :: [Type]) (r :: [Type]). Int -> PackedReader a r ()
unsafeSkipN :: forall (a :: [*]) (r :: [*]). Int -> PackedReader a r ()
unsafeSkipN Int
n = (PackedFragment (a :++: r) -> Identity ((), PackedFragment r))
-> PackedReader a r ()
forall (p :: [*]) (r :: [*]) v.
(PackedFragment (p :++: r) -> Identity (v, PackedFragment r))
-> PackedReader p r v
mkPackedReader ((PackedFragment (a :++: r) -> Identity ((), PackedFragment r))
 -> PackedReader a r ())
-> (PackedFragment (a :++: r) -> Identity ((), PackedFragment r))
-> PackedReader a r ()
forall a b. (a -> b) -> a -> b
$ \(PF Ptr Word8
ptr Int
l) -> ((), PackedFragment r) -> Identity ((), PackedFragment r)
forall a. a -> Identity a
forall (m :: * -> *) a. Monad m => a -> m a
return ((), Ptr Word8 -> Int -> PackedFragment r
forall (p :: [*]). Ptr Word8 -> Int -> PackedFragment p
PF (Ptr Word8
ptr Ptr Word8 -> Int -> Ptr Word8
forall a b. Ptr a -> Int -> Ptr b
`plusPtr` Int
n) (Int
l Int -> Int -> Int
forall a. Num a => a -> a -> a
- Int
n))