haskell-updater-1.5.0.0: src/Distribution/Gentoo/Util.hs
{- |
Module : Distribution.Gentoo.Util
Description : Utility functions
Copyright : (c) Ivan Lazar Miljenovic 2009
License : GPL-2 or later
Common utility functions.
-}
{-# LANGUAGE DeriveTraversable #-}
module Distribution.Gentoo.Util
( -- * Misc
BSFilePath
, concatMapM
, breakAll
-- * These
, These(..)
, these
-- * NESet
, NESet(..)
, singletonNE
, insertNE
, memberNE
, toListNE
) where
import Data.Bifoldable
import Data.Bifunctor
import Data.Bitraversable
import qualified Data.List as L
import qualified Data.Set as S
import Data.ByteString.Char8(ByteString)
-- | Alias used to indicate that this ByteString represents a FilePath
type BSFilePath = ByteString
-- | @concatMapM f = fmap concat . traverse f@
concatMapM :: (a -> IO [b]) -> [a] -> IO [b]
concatMapM f = fmap concat . traverse f
-- | @breakAll p = L.groupBy (const (not . p))@
breakAll :: (a -> Bool) -> [a] -> [[a]]
breakAll p = L.groupBy (const (not . p))
-- | Taken from the [these](https://hackage.haskell.org/package/these) package,
-- the t'These' type represents values with two non-exclusive possibilities.
--
-- This can be useful to represent combinations of two values, where the
-- combination is defined if either input is.
data These a b
= These a b
| This a
| That b
deriving (Show, Eq, Ord, Functor, Foldable, Traversable)
instance Bifunctor These where
bimap f g (These a b) = These (f a) (g b)
bimap f _ (This a) = This (f a)
bimap _ g (That b) = That (g b)
instance Bifoldable These where
bifoldMap f g (These a b) = f a <> g b
bifoldMap f _ (This a) = f a
bifoldMap _ g (That b) = g b
instance Bitraversable These where
bitraverse f g (These a b) = These <$> f a <*> g b
bitraverse f _ (This a) = This <$> f a
bitraverse _ g (That b) = That <$> g b
-- | Case analysis for the t'These' type.
these :: (a -> b -> c) -> (a -> c) -> (b -> c) -> These a b -> c
these f _ _ (These a b) = f a b
these _ g _ (This a) = g a
these _ _ h (That b) = h b
-- | A 'S.Set' which can never be empty.
data NESet a = a :~ S.Set a
deriving (Show, Eq, Ord, Foldable)
instance Ord a => Semigroup (NESet a) where
(x1 :~ s1) <> (x2 :~ s2) =
x1 :~ (if x1 == x2 then id else (S.insert x2)) (s1 <> s2)
-- | Create a 'NESet' from a single value.
singletonNE :: a -> NESet a
singletonNE x = x :~ S.empty
-- | Insert a value into a 'NESet'.
insertNE :: Ord a => a -> NESet a -> NESet a
insertNE x n@(y :~ s)
| x == y = n
| otherwise = y :~ S.insert x s
-- | Check if a value exists in a 'NESet'.
memberNE :: Ord a => a -> NESet a -> Bool
memberNE x (y :~ s) = x == y || S.member x s
-- | Convert a 'NESet' to a list. The ordering is defined by 'S.toList' of
-- 'S.Set'.
toListNE :: Ord a => NESet a -> [a]
toListNE (x :~ s) = S.toList (S.insert x s)