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

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

import Data.Int
import Data.Word
import HaskellWorks.Data.Container

import qualified Data.ByteString      as BS
import qualified Data.Vector          as DV
import qualified Data.Vector.Storable as DVS

-- | Class of values that support vector like operations
class Container v => Generate v where
  generate :: Int -> (Int -> Elem v) -> v

instance Generate String where
  generate :: Int -> (Int -> Elem String) -> String
generate Int
n Int -> Elem String
f = Int -> Elem String
f forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
`fmap` [Int
0 .. (Int
n forall a. Num a => a -> a -> a
- Int
1)]
  {-# INLINE generate #-}

instance Generate BS.ByteString where
  generate :: Int -> (Int -> Elem ByteString) -> ByteString
generate Int
n Int -> Elem ByteString
f = forall a b. (a, b) -> a
fst (forall a.
Int -> (a -> Maybe (Word8, a)) -> a -> (ByteString, Maybe a)
BS.unfoldrN Int
n Int -> Maybe (Word8, Int)
go Int
0)
    where go :: Int -> Maybe (Word8, Int)
go Int
i = if Int
i forall a. Eq a => a -> a -> Bool
/= Int
n then forall a. a -> Maybe a
Just (Int -> Elem ByteString
f Int
i, Int
i forall a. Num a => a -> a -> a
+ Int
1) else forall a. Maybe a
Nothing
  {-# INLINE generate #-}

instance Generate (DV.Vector Word8) where
  generate :: Int -> (Int -> Elem (Vector Word8)) -> Vector Word8
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Word16) where
  generate :: Int -> (Int -> Elem (Vector Word16)) -> Vector Word16
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Word32) where
  generate :: Int -> (Int -> Elem (Vector Word32)) -> Vector Word32
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Word64) where
  generate :: Int -> (Int -> Elem (Vector Word64)) -> Vector Word64
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Word8) where
  generate :: Int -> (Int -> Elem (Vector Word8)) -> Vector Word8
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Word16) where
  generate :: Int -> (Int -> Elem (Vector Word16)) -> Vector Word16
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Word32) where
  generate :: Int -> (Int -> Elem (Vector Word32)) -> Vector Word32
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Word64) where
  generate :: Int -> (Int -> Elem (Vector Word64)) -> Vector Word64
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Int8) where
  generate :: Int -> (Int -> Elem (Vector Int8)) -> Vector Int8
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Int16) where
  generate :: Int -> (Int -> Elem (Vector Int16)) -> Vector Int16
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Int32) where
  generate :: Int -> (Int -> Elem (Vector Int32)) -> Vector Int32
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DV.Vector Int64) where
  generate :: Int -> (Int -> Elem (Vector Int64)) -> Vector Int64
generate = forall a. Int -> (Int -> a) -> Vector a
DV.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Int8) where
  generate :: Int -> (Int -> Elem (Vector Int8)) -> Vector Int8
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Int16) where
  generate :: Int -> (Int -> Elem (Vector Int16)) -> Vector Int16
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Int32) where
  generate :: Int -> (Int -> Elem (Vector Int32)) -> Vector Int32
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Int64) where
  generate :: Int -> (Int -> Elem (Vector Int64)) -> Vector Int64
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}

instance Generate (DVS.Vector Int) where
  generate :: Int -> (Int -> Elem (Vector Int)) -> Vector Int
generate = forall a. Storable a => Int -> (Int -> a) -> Vector a
DVS.generate
  {-# INLINE generate #-}