{-# LANGUAGE CPP #-}
-- #define TEST
#ifdef TEST
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TemplateHaskell #-}
#endif
{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}

-- | 'Data.Serialize' functions for 'Data.Vector.Generic.Vector'
-- vectors. Orphan instances are provided for 'Data.Vector' and
-- 'Data.Vector.Primitive' vectors.
--
-- Instances are /not/ provided for 'Data.Vector.Unbox' vectors, as
-- they must be declared on an individual basis for each type the
-- vectors may contain. The 'genericGet' and 'genericPut' functions
-- should still work for these vectors without declaring instances.
-- 
-- The serialized format is an 'Int64' representing the
-- length of the 'Vector', followed by the serialized contents of each
-- element.
-- 
-- Note that the instances specialized for 'Data.Vector.Storable' are
-- much more performant for storable vectors.
#ifndef TEST
module Data.Vector.Serialize (genericGetVector, genericPutVector) where
#endif

import Control.Monad

import Data.Int (Int64)
import Data.Serialize (Get, Putter, Serialize(..))
import qualified Data.Vector as V
import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Generic as VG

#ifdef TEST
import Data.Serialize (decode, encode)
import Data.Vector.Storable.Serialize ()
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Unboxed as VU
import Test.QuickCheck.All
#endif

-- | Read a 'Data.Vector.Generic.Vector'.
genericGetVector :: (Serialize a, VG.Vector v a) => Get (v a)
genericGetVector = do 
  len64 <- get :: Get Int64
  when (len64 > fromIntegral (maxBound :: Int)) $
    fail "Host can't deserialize a Vector longer than (maxBound :: Int)"
  VG.replicateM (fromIntegral len64) get

-- | Write a 'Data.Vector.Generic.Vector'.
genericPutVector :: (Serialize a, VG.Vector v a) => Putter (v a)
genericPutVector v = do
  put ((fromIntegral $ VG.length v) :: Int64)
  VG.mapM_ put v

instance (Serialize a) => Serialize (V.Vector a) where
  get = genericGetVector ; put = genericPutVector

instance (Serialize a, VP.Prim a) => Serialize (VP.Vector a) where
  get = genericGetVector ; put = genericPutVector

#ifdef TEST
prop_vec :: [Int] -> Bool
prop_vec xs = Right xsv == decode (encode xsv)
  where xsv = V.fromList xs

prop_vec_tuple :: [[Int]] -> [Either [Bool] Double] -> Bool
prop_vec_tuple xs ys = Right (xsv, ysv) == decode (encode (xsv, ysv))
  where (xsv, ysv) = (V.fromList xs, V.fromList ys)

prop_prim :: [Int] -> Bool
prop_prim xs = Right xsv == decode (encode xsv)
  where xsv = VP.fromList xs

instance Serialize (VU.Vector Int) where
  get = genericGetVector ; put = genericPutVector

prop_unbox :: [Int] -> Bool
prop_unbox xs = Right xsv == decode (encode xsv)
  where xsv = VU.fromList xs

prop_storable :: [Int] -> Bool
prop_storable xs = Right xsv == decode (encode xsv)
  where xsv = VS.fromList xs

prop_storable_tuple :: [Int64] -> [Double] -> Bool
prop_storable_tuple xs ys = Right (xsv, ysv) == decode (encode (xsv, ysv))
  where (xsv, ysv) = (VS.fromList xs, VS.fromList ys)

main :: IO ()
main = void $ $quickCheckAll
#endif