packages feed

mischief-ecs-0.2.0.0: src/Mischief/ECS/Utils.hs

module Mischief.ECS.Utils where

import Data.Data
import Data.Either (fromRight)
import Data.Foldable
import Data.Kind
import Data.Maybe
import Data.Text (Text)
import Data.Text qualified as T
import GHC.Stack
import Unsafe.Coerce (unsafeCoerce)

class GetRep t where
  getRep :: t -> TypeRep

findM :: forall (m :: Type -> Type) a t. (Monad m, Foldable t) => (a -> m Bool) -> t a -> m (Maybe a)
findM f l = f' f (toList l)
  where
    f' _ [] = pure Nothing
    f' f (x : xs) = do
      b <- f x
      if b
        then
          pure $ Just x
        else
          findM f xs

class (Functor f) => Unwrappable f where
  unwrap' :: (HasCallStack) => Text -> f a -> a

instance Unwrappable Maybe where
  unwrap' t a = withFrozenCallStack $ fromMaybe (error $ T.unpack t) a

instance Unwrappable (Either a) where
  unwrap' t a = withFrozenCallStack $ fromRight (error $ T.unpack t) a

-- | Unwrap a 'Maybe' or 'Either', panicking if it doesn't contain a value.
unwrap :: (HasCallStack, Unwrappable f) => f a -> a
unwrap = withFrozenCallStack $ unwrap' ""

-- | Unwrap a 'Maybe' or 'Either', throwing the given error if it doesn't contain a value.
expect :: (HasCallStack, Unwrappable f) => Text -> f a -> a
expect t = withFrozenCallStack $ unwrap' t

andM :: (Traversable t, Applicative f) => t (f Bool) -> f Bool
andM t = and <$> sequenceA t

orM :: (Traversable t, Applicative f) => t (f Bool) -> f Bool
orM t = or <$> sequenceA t

anyM :: (Traversable t, Monad f) => (a -> f Bool) -> t a -> f Bool
anyM f t = do
  bools <- traverse f t
  pure $ or bools

mapLeft :: (a -> c) -> Either a b -> Either c b
mapLeft _ (Right a) = Right a
mapLeft f (Left a) = Left $ f a

data ErasedValue where
  ErasedValue :: forall a. (Typeable a) => a -> ErasedValue

eraseValue :: forall a. (Typeable a) => a -> ErasedValue
eraseValue = ErasedValue

uneraseValue :: forall a. (Typeable a) => ErasedValue -> Maybe a
uneraseValue (ErasedValue (a :: b)) =
  case eqT @a @b of
    Nothing -> Nothing
    Just Refl -> Just a

unsafeUneraseValue :: forall a. ErasedValue -> a
unsafeUneraseValue (ErasedValue a) = unsafeCoerce a

fromMaybeM :: (Applicative m) => m a -> Maybe a -> m a
fromMaybeM m = maybe m pure