module Vulkan.Utils.Misc ( -- * Sorting things partitionOptReq , partitionOptReqIO -- * Bit Utils , showBits , (.&&.) ) where import Control.Monad.IO.Class import Data.Bits import Data.Foldable import Data.List ( intercalate , partition ) import Vulkan.Utils.Internal -- | From a list of things, take all the required things and as many optional -- things as possible. partitionOptReq :: Eq a => [a] -- ^ What do we have available -> [a] -- ^ Optional desired elements -> [a] -- ^ Required desired elements -> ([a], Either [a] [a]) -- ^ (Missing optional elements, Either (missing required elements) or (all -- required elements and as many optional elements as possible) partitionOptReq available optional required = let (optHave, optMissing) = partition (`elem` available) optional (reqHave, reqMissing) = partition (`elem` available) required in ( optMissing , case reqMissing of [] -> Right (reqHave <> optHave) xs -> Left xs ) -- | Like 'partitionOptReq'. -- -- Will throw an 'IOError in the case of missing things. Details on missing -- things will be reported in stderr. -- -- This is useful in dealing with layers and extensions. partitionOptReqIO :: (Show a, Eq a, MonadIO m) => String -- ^ What are we sorting (Used for a debug message) -> [a] -- ^ What do we have available -> [a] -- ^ Optional desired elements -> [a] -- ^ Required desired elements -> m ([a],[a]) -- ^ All the required elements and as many optional elements as possible, -- as well as the missing optional elements. partitionOptReqIO type' available optional required = liftIO $ do let (optMissing, exts) = partitionOptReq available optional required for_ optMissing $ \o -> sayErr $ "Missing optional " <> type' <> ": " <> show o case exts of Left reqMissing -> do for_ reqMissing $ \r -> sayErr $ "Missing required " <> type' <> ": " <> show r noSuchThing $ "Don't have all required " <> type' <> "s" Right xs -> pure (xs, optMissing) ---------------------------------------------------------------- -- * Bit utils ---------------------------------------------------------------- -- | Show valies as a union of their individual bits -- -- >>> showBits @Int 5 -- "1 .|. 4" -- -- >>> showBits @Int 0 -- "zeroBits" -- -- >>> import Vulkan.Core10.Enums.QueueFlagBits -- >>> showBits (QUEUE_COMPUTE_BIT .|. QUEUE_GRAPHICS_BIT) -- "QUEUE_GRAPHICS_BIT .|. QUEUE_COMPUTE_BIT" showBits :: forall a . (Show a, FiniteBits a) => a -> String showBits a = if a == zeroBits then "zeroBits" else intercalate " .|. " $ fmap show (setBits a) -- | The list of bits which are set setBits :: FiniteBits a => a -> [a] setBits a = [ b | -- lol, is this really necessary p <- [countTrailingZeros a .. finiteBitSize a - countLeadingZeros a - 1] , let b = bit p , a .&&. b ] -- | Check if the intersection of bits is non-zero (.&&.) :: Bits a => a -> a -> Bool x .&&. y = (x .&. y) /= zeroBits