module Crypto.Saltine.Internal.Util where
import Foreign.C
import Foreign.Marshal.Alloc (mallocBytes)
import Foreign.Ptr
import System.IO.Unsafe
import Control.Applicative
import qualified Data.ByteString as S
import Data.ByteString (ByteString)
import Data.ByteString.Unsafe
import Data.Monoid
cycleSucc :: (Bounded a, Enum a, Eq a) => a -> (Bool, a)
cycleSucc a = (top, if top then minBound else succ a)
where top = a == maxBound
nudgeBS :: ByteString -> ByteString
nudgeBS i = fst $ S.unfoldrN (S.length i) go (True, i) where
go (toSucc, bs) = do
(hd, tl) <- S.uncons bs
let (top, hd') = cycleSucc hd
if toSucc
then return (hd', (top, tl))
else return (hd, (top && toSucc, tl))
orbit :: Eq a => (a -> a) -> a -> [a]
orbit f a0 = orbit' (f a0) where
orbit' a = if a == a0 then [a0] else a : orbit' (f a)
pad :: Int -> ByteString -> ByteString
pad n = mappend (S.replicate n 0)
unpad :: Int -> ByteString -> ByteString
unpad = S.drop
handleErrno :: CInt -> (a -> Either String a)
handleErrno err a = case err of
0 -> Right a
-1 -> Left "failed"
n -> Left ("unexpected error code: " ++ show n)
unsafeDidSucceed :: IO CInt -> Bool
unsafeDidSucceed = go . unsafePerformIO
where go 0 = True
go _ = False
constByteStrings :: [ByteString] -> ([CStringLen] -> IO b) -> IO b
constByteStrings =
foldr (\v kk -> \k -> (unsafeUseAsCStringLen v) (\a -> kk (\as -> k (a:as)))) ($ [])
buildUnsafeByteString' :: Int -> (Ptr CChar -> IO b) -> IO (b, ByteString)
buildUnsafeByteString' n k = do
ph <- mallocBytes n
bs <- unsafePackMallocCStringLen (ph, fromIntegral n)
out <- unsafeUseAsCString bs k
return (out, bs)
buildUnsafeByteString :: Int -> (Ptr CChar -> IO b) -> (b, ByteString)
buildUnsafeByteString n = unsafePerformIO . buildUnsafeByteString' n
randomByteString :: Int -> IO ByteString
randomByteString n =
snd <$> buildUnsafeByteString' n (`c_randombytes_buf` fromIntegral n)
hush :: Either s a -> Maybe a
hush = either (const Nothing) Just
foreign import ccall "randombytes_buf"
c_randombytes_buf :: Ptr CChar -> CInt -> IO ()