{-|
Module      : Control.Lens.Extra
Description : Extra utility functions for working with lenses.

Copyright   : (c) Henry J. Wylde, 2016
License     : BSD3
Maintainer  : public@hjwylde.com

Extra utility functions for working with lenses.
-}

{-# LANGUAGE Rank2Types #-}

module Control.Lens.Extra (
    module Control.Lens,

    -- * Folds
    is, isn't, hasuse, hasn'tuse,

    -- * Traversals
    filteredBy,
) where

import Control.Lens hiding (isn't)
import Control.Monad.State

import Data.Monoid

-- | The counter-part to 'isn't', but more general as it takes a 'Getting' instead.
--
--   @'is' = 'has'@
is :: Getting Any s a -> s -> Bool
is = has

-- | A re-write of 'Control.Lens.Prism.isn't' to be more general by taking a 'Getting' instead.
--
--   @'isn't' = 'hasn't'@
isn't :: Getting All s a -> s -> Bool
isn't = hasn't

-- | Check to see if this 'Fold' or 'Traversal' matches 1 or more entries in the current state.
--
--   @'hasuse' = 'gets' . 'has'@
hasuse :: MonadState s m => Getting Any s a -> m Bool
hasuse = gets . has

-- | Check to see if this 'Fold' or 'Traversal' has no matches in the current state.
--
--   @'hasn'tuse' = 'gets' . 'hasn't'@
hasn'tuse :: MonadState s m => Getting All s a -> m Bool
hasn'tuse = gets . hasn't

-- | A companion to 'filtered' that, rather than using a predicate, filters on the given lens for
-- matches.
filteredBy :: Eq b => Lens' a b -> b -> Traversal' a a
filteredBy lens value = filtered ((value ==) . view lens)