{-# LANGUAGE ImportQualifiedPost #-}

module Sel.Internal.Sodium where

import Control.Monad.Trans.Class (lift)
import Data.ByteString (StrictByteString)
import Data.ByteString qualified as ByteString
import Foreign (ForeignPtr)
import Foreign.C (CSize, CUChar)
import LibSodium.Bindings.Utils
import System.IO.Unsafe (unsafeDupablePerformIO)

import Sel.Internal.Scoped
import Sel.Internal.Scoped.Foreign

-- | Convert a byte array to a hexadecimal-encoded 'StrictByteString' in constant time.
--
-- /See:/ [@sodium_bin2hex@](https://libsodium.gitbook.io/doc/helpers#hexadecimal-encoding-decoding)
--
-- @since 0.0.3.0
binaryToHex :: ForeignPtr CUChar -> CSize -> StrictByteString
binaryToHex :: ForeignPtr CUChar -> CSize -> StrictByteString
binaryToHex ForeignPtr CUChar
fPtr CSize
size = IO StrictByteString -> StrictByteString
forall a. IO a -> a
unsafeDupablePerformIO (IO StrictByteString -> StrictByteString)
-> (Scoped IO StrictByteString -> IO StrictByteString)
-> Scoped IO StrictByteString
-> StrictByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Scoped IO StrictByteString -> IO StrictByteString
forall (m :: * -> *) a. Applicative m => Scoped m a -> m a
use (Scoped IO StrictByteString -> StrictByteString)
-> Scoped IO StrictByteString -> StrictByteString
forall a b. (a -> b) -> a -> b
$ do
  let hexLength :: CSize
hexLength = CSize
size CSize -> CSize -> CSize
forall a. Num a => a -> a -> a
* CSize
2 CSize -> CSize -> CSize
forall a. Num a => a -> a -> a
+ CSize
1
  hexPtr <- ForeignPtr CChar -> Scoped IO (Ptr CChar)
forall a. ForeignPtr a -> Scoped IO (Ptr a)
foreignPtr (ForeignPtr CChar -> Scoped IO (Ptr CChar))
-> Scoped IO (ForeignPtr CChar) -> Scoped IO (Ptr CChar)
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< Int -> Scoped IO (ForeignPtr CChar)
forall a. Int -> Scoped IO (ForeignPtr a)
mallocForeignPtrBytes (CSize -> Int
forall a b. (Integral a, Num b) => a -> b
fromIntegral CSize
hexLength)
  ptr <- foreignPtr fPtr
  lift $ ByteString.packCString =<< sodiumBin2Hex hexPtr hexLength ptr size