module Botan.Prelude
( module Prelude
, module Control.Applicative
, module Control.Monad
, module Control.Monad.IO.Class
, module Control.Exception
, module Control.DeepSeq
, module Data.Bits
, module Data.ByteString
, module Data.Text
, module Data.Foldable
, module Data.Word
, module System.IO
, module System.IO.Unsafe
, module GHC.Stack
, Message(..)
, Ciphertext(..)
, LazyCiphertext(..)
, Plaintext(..)
, unsafePerformIO1
, unsafePerformIO2
, unsafePerformIO3
, unsafePerformIO4
-- , strictReturn
-- , strictly
-- , strictPerformIO
-- , strictPerformIO1
-- , strictPerformIO2
-- , strictPerformIO3
, showText
, showBytes
--
, module Data.IORef
, track
--
, splitBlocks
) where

-- Re-exported modules

import Prelude

import Control.Applicative
import Control.Monad
import Control.Monad.IO.Class
import Control.Exception
import Control.DeepSeq


import Data.Bits

import Data.ByteString (ByteString)
import Data.Text (Text)

import Data.Foldable

import Data.Word

import System.IO
import System.IO.Unsafe

import GHC.Stack

import Data.IORef

-- Internal imports

import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Char8 as Char8
import qualified Data.ByteString.Lazy as Lazy
import qualified Data.Text as Text

--

-- TODO: Vanish these...
type Message = ByteString
type Plaintext = ByteString
type Ciphertext = ByteString
type LazyCiphertext = Lazy.ByteString

--

unsafePerformIO1 :: (a -> IO b) -> a -> b
unsafePerformIO1 :: forall a b. (a -> IO b) -> a -> b
unsafePerformIO1 = (IO b -> b
forall a. IO a -> a
unsafePerformIO (IO b -> b) -> (a -> IO b) -> a -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
.)
{-# INLINE unsafePerformIO1 #-}

unsafePerformIO2 :: (a -> b -> IO c) -> a -> b -> c
unsafePerformIO2 :: forall a b c. (a -> b -> IO c) -> a -> b -> c
unsafePerformIO2 = ((b -> IO c) -> b -> c
forall a b. (a -> IO b) -> a -> b
unsafePerformIO1 ((b -> IO c) -> b -> c) -> (a -> b -> IO c) -> a -> b -> c
forall b c a. (b -> c) -> (a -> b) -> a -> c
.)
{-# INLINE unsafePerformIO2 #-}

unsafePerformIO3 :: (a -> b -> c -> IO d) -> a -> b -> c -> d
unsafePerformIO3 :: forall a b c d. (a -> b -> c -> IO d) -> a -> b -> c -> d
unsafePerformIO3 = ((b -> c -> IO d) -> b -> c -> d
forall a b c. (a -> b -> IO c) -> a -> b -> c
unsafePerformIO2 ((b -> c -> IO d) -> b -> c -> d)
-> (a -> b -> c -> IO d) -> a -> b -> c -> d
forall b c a. (b -> c) -> (a -> b) -> a -> c
.)
{-# INLINE unsafePerformIO3 #-}

unsafePerformIO4 :: (a -> b -> c -> d -> IO e) -> a -> b -> c -> d -> e
unsafePerformIO4 :: forall a b c d e.
(a -> b -> c -> d -> IO e) -> a -> b -> c -> d -> e
unsafePerformIO4 = ((b -> c -> d -> IO e) -> b -> c -> d -> e
forall a b c d. (a -> b -> c -> IO d) -> a -> b -> c -> d
unsafePerformIO3 ((b -> c -> d -> IO e) -> b -> c -> d -> e)
-> (a -> b -> c -> d -> IO e) -> a -> b -> c -> d -> e
forall b c a. (b -> c) -> (a -> b) -> a -> c
.)
{-# INLINE unsafePerformIO4 #-}

-- NOTE: These strict and deeply strict functions are inspired by:
--  https://hackage.haskell.org/package/strict-io-0.2.2/docs/src/System-IO-Strict-Internals.html
-- Without the SIO monad, they are of dubious / unknown value at the moment.
-- Strictness may otherwise be achieved through $! and $!!

-- strictReturn :: (Monad m, NFData a) => a -> m a
-- strictReturn a = a `seq` return a
-- {-# INLINE strictReturn #-}

-- strictly :: (NFData a) => IO a -> IO a
-- strictly m = m >>= strictReturn
-- {-# INLINE strictly #-}

-- strictPerformIO :: (NFData a) => IO a -> a
-- strictPerformIO = unsafePerformIO . strictly
-- {-# INLINE strictPerformIO #-}

-- strictPerformIO1 :: (NFData b) => (a -> IO b) -> a -> b
-- strictPerformIO1 = (strictPerformIO .)
-- {-# INLINE strictPerformIO1 #-}

-- strictPerformIO2 :: (NFData c) => (a -> b -> IO c) -> a -> b -> c
-- strictPerformIO2 = (strictPerformIO1 .)
-- {-# INLINE strictPerformIO2 #-}

-- strictPerformIO3 :: (NFData d) => (a -> b -> c -> IO d) -> a -> b -> c -> d
-- strictPerformIO3 = (strictPerformIO2 .)
-- {-# INLINE strictPerformIO3 #-}

-- deepReturn :: (Monad m, NFData a) => a -> m a
-- deepReturn a = rnf a `seq` return a
-- {-# INLINE deepReturn #-}

-- deeply :: (NFData a) => IO a -> IO a
-- deeply m = m >>= deepReturn
-- {-# INLINE deeply #-}

-- deepPerformIO :: (NFData a) => IO a -> a
-- deepPerformIO = unsafePerformIO . deeply
-- {-# INLINE deepPerformIO #-}

-- deepPerformIO1 :: (NFData b) => (a -> IO b) -> a -> b
-- deepPerformIO1 = (deepPerformIO .)
-- {-# INLINE deepPerformIO1 #-}

-- deepPerformIO2 :: (NFData c) => (a -> b -> IO c) -> a -> b -> c
-- deepPerformIO2 = (deepPerformIO1 .)
-- {-# INLINE deepPerformIO2 #-}

-- deepPerformIO3 :: (NFData d) => (a -> b -> c -> IO d) -> a -> b -> c -> d
-- deepPerformIO3 = (deepPerformIO2 .)
-- {-# INLINE deepPerformIO3 #-}

showText :: (Show a) => a -> Text
showText :: forall a. Show a => a -> Text
showText = String -> Text
Text.pack (String -> Text) -> (a -> String) -> a -> Text
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show

showBytes :: (Show a) => a -> ByteString
showBytes :: forall a. Show a => a -> ByteString
showBytes = String -> ByteString
Char8.pack (String -> ByteString) -> (a -> String) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> String
forall a. Show a => a -> String
show

-- From: https://stackoverflow.com/questions/28687384/test-if-a-value-has-been-evaluated-to-weak-head-normal-form
-- import Data.IORef
-- import System.IO.Unsafe
track :: a -> IO (a, IO Bool)
track :: forall a. a -> IO (a, IO Bool)
track a
val = do
    IORef Bool
ref <- Bool -> IO (IORef Bool)
forall a. a -> IO (IORef a)
newIORef Bool
False
    (a, IO Bool) -> IO (a, IO Bool)
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return
        ( IO () -> ()
forall a. IO a -> a
unsafePerformIO (IORef Bool -> Bool -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef Bool
ref Bool
True) () -> a -> a
forall a b. a -> b -> b
`seq` a
val
        , IORef Bool -> IO Bool
forall a. IORef a -> IO a
readIORef IORef Bool
ref
        )

-- A name type

data Name
    = Name ByteString           -- Foo
    | NameFn ByteString [Name]  -- Foo(a,b,...,c)
    | Names [Name]              -- a/b/.../c
    | Param Int

nameBytes :: Name -> ByteString
nameBytes :: Name -> ByteString
nameBytes (Name ByteString
name) = ByteString
name
nameBytes (NameFn ByteString
name [Name]
args) = ByteString
name ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
"(" ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
inner ByteString -> ByteString -> ByteString
forall a. Semigroup a => a -> a -> a
<> ByteString
")" where
    inner :: ByteString
inner = ByteString -> [ByteString] -> ByteString
ByteString.intercalate ByteString
"," ([ByteString] -> ByteString) -> [ByteString] -> ByteString
forall a b. (a -> b) -> a -> b
$ (Name -> ByteString) -> [Name] -> [ByteString]
forall a b. (a -> b) -> [a] -> [b]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap Name -> ByteString
nameBytes [Name]
args

-- TODO: Name parser

-- TODO: Parser for custom Modular Crypt Format
--  Like: https://passlib.readthedocs.io/en/stable/modular_crypt_format.html#mcf-identifiers

-- #mode$alg:content or something

splitBlocks :: Int -> ByteString -> [ByteString]
splitBlocks :: Int -> ByteString -> [ByteString]
splitBlocks Int
blockSize = ByteString -> [ByteString]
go where
    go :: ByteString -> [ByteString]
go ByteString
bytes =  case Int -> ByteString -> (ByteString, ByteString)
ByteString.splitAt Int
blockSize ByteString
bytes of
        (ByteString
block,ByteString
"")      -> [ByteString
block]
        (ByteString
block,ByteString
rest)    -> ByteString
block ByteString -> [ByteString] -> [ByteString]
forall a. a -> [a] -> [a]
: ByteString -> [ByteString]
go ByteString
rest