content: {-# LANGUAGE CPP #-}
  {-# LANGUAGE OverloadedStrings #-}
  
  module Network.QUIC.Utils where
  
  import Control.Exception
  import Control.Monad (replicateM)
  import qualified Data.ByteString as BS
  import Data.ByteString.Base16
  import qualified Data.ByteString.Char8 as C8
  import Data.ByteString.Internal (ByteString (..))
  import Data.ByteString.Short (ShortByteString)
  import qualified Data.ByteString.Short as Short
  import Data.Char (chr)
  #if __GLASGOW_HASKELL__ < 910
  import Data.List (foldl')
  #endif
  import Data.Word
  import Foreign.ForeignPtr (withForeignPtr)
  import Foreign.Ptr (Ptr, plusPtr)
  import System.Random (randomIO)
  
  -- GHC 8.0 does not provide fromRight.
  fromRight :: b -> Either a b -> b
  fromRight _ (Right b) = b
  fromRight b _ = b
  
  dec16 :: ByteString -> ByteString
  dec16 = fromRight "" . decode
  
  enc16 :: ByteString -> ByteString
  enc16 = encode
  
  dec16s :: ShortByteString -> ShortByteString
  dec16s = Short.toShort . fromRight "" . decode . Short.fromShort
  
  enc16s :: ShortByteString -> ShortByteString
  enc16s = Short.toShort . encode . Short.fromShort
  
  shortToString :: ShortByteString -> String
  shortToString = map (chr . fromIntegral) . Short.unpack
  
  getRandomOneByte :: IO Word8
  getRandomOneByte = randomIO
  
  getRandomBytes :: Int -> IO ShortByteString
  getRandomBytes n = Short.pack <$> replicateM n getRandomOneByte
  
  {-# INLINE totalLen #-}
  totalLen :: [ByteString] -> Int
  totalLen = foldl' (\n bs -> n + BS.length bs) 0
  
  sum' :: (Functor f, Foldable f) => f Int -> Int
  sum' = foldl' (+) 0
  
  withByteString :: ByteString -> (Ptr Word8 -> IO a) -> IO a
  withByteString (PS fptr off _) f = withForeignPtr fptr $ \ptr ->
      f (ptr `plusPtr` off)
  
  shortpack :: String -> ShortByteString
  shortpack = Short.toShort . C8.pack
  
  ignore :: SomeException -> IO ()
  ignore se
      | isAsyncException se = throwIO se
      | otherwise = return ()
  
  isAsyncException :: Exception e => e -> Bool
  isAsyncException e =
      case fromException (toException e) of
          Just (SomeAsyncException _) -> True
          Nothing -> False
  
  throughAsync :: IO a -> SomeException -> IO a
  throughAsync action (SomeException e)
      | isAsyncException e = throwIO e
      | otherwise = action
  