{-# LANGUAGE FlexibleInstances     #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies          #-}

module HaskellWorks.Data.Uncons
    ( Container(..)
    , Uncons(..)
    ) where

import qualified Data.ByteString               as BS
import           Data.Int
import           Data.Maybe
import qualified Data.Vector                   as DV
import qualified Data.Vector.Storable          as DVS
import           Data.Word
import           HaskellWorks.Data.Container
import           HaskellWorks.Data.Drop
import           Prelude hiding (drop)

class Drop v => Uncons v where
  uncons :: v -> Maybe (Elem v, v)

instance Uncons String where
  uncons s = case s of
    (x:xs)  -> Just (x, xs)
    _       -> Nothing
  {-# INLINE uncons   #-}

instance Uncons BS.ByteString where
  uncons = BS.uncons
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Word8) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Word16) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Word32) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Word64) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Word8) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Word16) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Word32) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Word64) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Int8) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Int16) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Int32) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DV.Vector Int64) where
  uncons s = if DV.length s == 0 then Nothing else Just (DV.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Int8) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Int16) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Int32) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Int64) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}

instance Uncons (DVS.Vector Int) where
  uncons s = if DVS.length s == 0 then Nothing else Just (DVS.head s, drop 1 s)
  {-# INLINE uncons   #-}