{-# LANGUAGE CPP #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE MultiWayIf #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module Test.SmallCheck.Series.Instances () where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>), pure)
#endif
#if !MIN_VERSION_smallcheck(1,1,4)
import Control.Applicative ((<|>), empty)
import Control.Monad.Logic (interleave)
import Data.Int
import Data.Word
#endif
import qualified Data.Map as Map
import Data.Map (Map)
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.Text as T
import qualified Data.Text.Lazy as TL
import Test.SmallCheck.Series
#if !MIN_VERSION_smallcheck(1,1,4)
instance Monad m => Serial m Int8 where series = ints
instance Monad m => CoSerial m Int8 where coseries = coInts
instance Monad m => Serial m Int16 where series = ints
instance Monad m => CoSerial m Int16 where coseries = coInts
instance Monad m => Serial m Int32 where series = ints
instance Monad m => CoSerial m Int32 where coseries = coInts
instance Monad m => Serial m Int64 where series = ints
instance Monad m => CoSerial m Int64 where coseries = coInts
ints :: (Monad m, Integral n, Bounded n) => Series m n
ints = generate (\d -> if d >= 0 then pure 0 else empty) <|>
nats `interleave` (fmap negate nats)
where
nats = generate $ \d -> take d [1..maxBound]
coInts :: (Integral n, CoSerial m n) => Series m b -> Series m (n -> b)
coInts rs =
alts0 rs >>- \z ->
alts1 rs >>- \f ->
alts1 rs >>- \g ->
return $ \i -> if
| i > 0 -> f (i - 1)
| i < 0 -> g ((abs i - 1))
| otherwise -> z
#if !MIN_VERSION_smallcheck(1,1,3)
instance Monad m => Serial m Word where series = nats0
instance Monad m => CoSerial m Word where coseries = conats0
#endif
instance Monad m => Serial m Word8 where series = nats0
instance Monad m => CoSerial m Word8 where coseries = conats0
instance Monad m => Serial m Word16 where series = nats0
instance Monad m => CoSerial m Word16 where coseries = conats0
instance Monad m => Serial m Word32 where series = nats0
instance Monad m => CoSerial m Word32 where coseries = conats0
instance Monad m => Serial m Word64 where series = nats0
instance Monad m => CoSerial m Word64 where coseries = conats0
nats0 :: (Integral n, Bounded n) => Series m n
nats0 = generate $ \d -> take (d+1) [0..maxBound]
conats0 :: (Integral a, CoSerial m a) => Series m b -> Series m (a -> b)
conats0 rs =
alts0 rs >>- \z ->
alts1 rs >>- \f ->
return $ \n ->
if n > 0
then f (n-1)
else z
#endif
instance Monad m => Serial m B.ByteString where
series = cons0 B.empty \/ cons2 B.cons
instance Monad m => CoSerial m B.ByteString where
coseries rs =
alts0 rs >>- \y ->
alts2 rs >>- \f ->
return $ \bs -> case B.uncons bs of
Nothing -> y
Just (b,bs') -> f (B.singleton b) bs'
instance Monad m => Serial m BL.ByteString where
series = cons0 BL.empty \/ cons2 BL.cons
instance Monad m => CoSerial m BL.ByteString where
coseries rs =
alts0 rs >>- \y ->
alts2 rs >>- \f ->
return $ \bs -> case BL.uncons bs of
Nothing -> y
Just (b,bs') -> f (BL.singleton b) bs'
instance Monad m => Serial m T.Text where
series = cons0 T.empty \/ cons2 T.cons
instance Monad m => CoSerial m T.Text where
coseries rs =
alts0 rs >>- \y ->
alts2 rs >>- \f ->
return $ \bs -> case T.uncons bs of
Nothing -> y
Just (b,bs') -> f (T.singleton b) bs'
instance Monad m => Serial m TL.Text where
series = cons0 TL.empty \/ cons2 TL.cons
instance Monad m => CoSerial m TL.Text where
coseries rs =
alts0 rs >>- \y ->
alts2 rs >>- \f ->
return $ \bs -> case TL.uncons bs of
Nothing -> y
Just (b,bs') -> f (TL.singleton b) bs'
instance (Serial m k, Serial m v) => Serial m (Map k v) where
series = Map.singleton <$> series <~> series
instance (Ord k, CoSerial m k, CoSerial m v) => CoSerial m (Map k v) where
coseries rs =
alts0 rs >>- \y ->
alts2 rs >>- \f ->
return $ \m -> case pop m of
Nothing -> y
Just ((k,v), m') -> f (Map.singleton k v) m'
where
pop m = case Map.toList m of
[] -> Nothing
(kv:its) -> Just (kv, Map.fromList its)