{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}

-- -------------------------------------------------------------------------- --
-- |
-- Module: Data.ByteString.Random.MWC
-- Copyright: (c) Lars Kuhtz <lakuhtz@gmail.com> 2017
-- License: MIT
-- Maintainer: lakuhtz@gmail.com
-- Stability: experimental

module Data.ByteString.Random.MWC
( random
, randomGen
) where

import Data.ByteString (ByteString)

import Numeric.Natural (Natural)

import System.Random.MWC (uniform, GenIO, withSystemRandom)

-- internal imports

import Data.ByteString.Random.Internal

-- -------------------------------------------------------------------------- --

instance (g ~ GenIO)  RandomWords g where
    uniformW8 :: g -> IO Word8
uniformW8 = g -> IO Word8
forall a (m :: * -> *).
(Variate a, PrimMonad m) =>
Gen (PrimState m) -> m a
uniform
    {-# INLINE uniformW8 #-}
    uniformW64 :: g -> IO Word64
uniformW64 = g -> IO Word64
forall a (m :: * -> *).
(Variate a, PrimMonad m) =>
Gen (PrimState m) -> m a
uniform
    {-# INLINE uniformW64 #-}

{-# SPECIALIZE generate  GenIO  Natural  IO ByteString #-}

-- -------------------------------------------------------------------------- --

randomGen
     GenIO
        -- ^ PRNG
     Natural
        -- ^ Length of the result bytestring in bytes
     IO ByteString
randomGen :: GenIO -> Natural -> IO ByteString
randomGen = GenIO -> Natural -> IO ByteString
forall g. RandomWords g => g -> Natural -> IO ByteString
generate
{-# INLINE randomGen #-}

-- $setup
-- >>> import qualified Data.ByteString as B
-- >>> import Test.QuickCheck

-- | Generate a random bytestring of length n. The PRNG is seeded
-- from the system randomness source.
--
-- prop> ioProperty $ ((fromIntegral n ===) . B.length) <$> random n
-- prop> n > 4 ==> ioProperty $ (/=) <$> random n <*> random n
--
random
     Natural
        -- ^ Length of the result bytestring in bytes
     IO ByteString
random :: Natural -> IO ByteString
random = (Gen RealWorld -> IO ByteString) -> IO ByteString
forall (m :: * -> *) a.
PrimBase m =>
(Gen (PrimState m) -> m a) -> IO a
withSystemRandom ((Gen RealWorld -> IO ByteString) -> IO ByteString)
-> (Natural -> Gen RealWorld -> IO ByteString)
-> Natural
-> IO ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Gen RealWorld -> Natural -> IO ByteString)
-> Natural -> Gen RealWorld -> IO ByteString
forall a b c. (a -> b -> c) -> b -> a -> c
flip Gen RealWorld -> Natural -> IO ByteString
GenIO -> Natural -> IO ByteString
randomGen