{-# LANGUAGE CPP #-}
-- | 'IntMap' is an instance of 'Optics.At.Core.At' and provides
-- 'Optics.At.Core.at' as a lens on values at keys:
--
-- >>> IntMap.fromList [(1, "world")] ^. at 1
-- Just "world"
--
-- >>> IntMap.empty & at 1 .~ Just "world"
-- fromList [(1,"world")]
--
-- >>> IntMap.empty & at 0 .~ Just "hello"
-- fromList [(0,"hello")]
--
-- We can traverse, fold over, and map over key-value pairs in an 'IntMap',
-- thanks to indexed traversals, folds and setters.
--
-- >>> iover imapped const $ IntMap.fromList [(1, "Venus")]
-- fromList [(1,1)]
--
-- >>> ifoldMapOf ifolded (\i _ -> Sum i) $ IntMap.fromList [(2, "Earth"), (3, "Mars")]
-- Sum {getSum = 5}
--
-- >>> itraverseOf_ ifolded (curry print) $ IntMap.fromList [(4, "Jupiter")]
-- (4,"Jupiter")
--
-- >>> itoListOf ifolded $ IntMap.fromList [(5, "Saturn")]
-- [(5,"Saturn")]
--
-- A related class, 'Optics.At.Core.Ixed', allows us to use 'Optics.At.Core.ix' to
-- traverse a value at a particular key.
--
-- >>> IntMap.fromList [(2, "Earth")] & ix 2 %~ ("New " ++)
-- fromList [(2,"New Earth")]
--
-- >>> preview (ix 8) IntMap.empty
-- Nothing
--
module Data.IntMap.Optics
  ( toMapOf
  , lt
  , gt
  , le
  , ge
  ) where

import Data.IntMap (IntMap)
import qualified Data.IntMap as IntMap

import Optics.IxAffineTraversal
import Optics.IxFold
import Optics.Optic

-- | Construct a map from an 'IxFold'.
--
-- The construction is left-biased (see 'IntMap.union'), i.e. the first occurrences of
-- keys in the fold or traversal order are preferred.
--
-- >>> toMapOf ifolded ["hello", "world"]
-- fromList [(0,"hello"),(1,"world")]
--
-- >>> toMapOf (folded % ifolded) [(1,"alpha"),(2, "beta")]
-- fromList [(1,"alpha"),(2,"beta")]
--
-- >>> toMapOf (icompose (\a b -> 10*a+b) $ ifolded % ifolded) ["foo", "bar"]
-- fromList [(0,'f'),(1,'o'),(2,'o'),(10,'b'),(11,'a'),(12,'r')]
--
-- >>> toMapOf (folded % ifolded) [(1, "hello"), (2, "world"), (1, "dummy")]
-- fromList [(1,"hello"),(2,"world")]
--
toMapOf
  :: (Is k A_Fold, is `HasSingleIndex` Int)
  => Optic' k is s a -> s -> IntMap a
toMapOf :: Optic' k is s a -> s -> IntMap a
toMapOf Optic' k is s a
o = Optic' k is s a -> (Key -> a -> IntMap a) -> s -> IntMap a
forall (k :: OpticKind) (m :: OpticKind) (is :: IxList)
       (i :: OpticKind) (s :: OpticKind) (a :: OpticKind).
(Is k A_Fold, Monoid m, HasSingleIndex is i) =>
Optic' k is s a -> (i -> a -> m) -> s -> m
ifoldMapOf Optic' k is s a
o Key -> a -> IntMap a
forall (a :: OpticKind). Key -> a -> IntMap a
IntMap.singleton
{-# INLINE toMapOf #-}

-- | Focus on the largest key smaller than the given one and its corresponding
-- value.
--
-- >>> IntMap.fromList [(1, "hi"), (2, "there")] & over (lt 2) (++ "!")
-- fromList [(1,"hi!"),(2,"there")]
--
-- >>> ipreview (lt 1) $ IntMap.fromList [(1, 'x'), (2, 'y')]
-- Nothing
lt :: Int -> IxAffineTraversal' Int (IntMap v) v
lt :: Key -> IxAffineTraversal' Key (IntMap v) v
lt Key
k = IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (i :: OpticKind) (s :: OpticKind) (t :: OpticKind)
       (a :: OpticKind) (b :: OpticKind).
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL (IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
 -> IxAffineTraversal' Key (IntMap v) v)
-> IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ \forall (r :: OpticKind). r -> f r
point Key -> v -> f v
f IntMap v
s ->
  case Key -> IntMap v -> Maybe (Key, v)
forall (a :: OpticKind). Key -> IntMap a -> Maybe (Key, a)
IntMap.lookupLT Key
k IntMap v
s of
    Maybe (Key, v)
Nothing      -> IntMap v -> f (IntMap v)
forall (r :: OpticKind). r -> f r
point IntMap v
s
    Just (Key
k', v
v) -> Key -> v -> f v
f Key
k' v
v f v -> (v -> IntMap v) -> f (IntMap v)
forall (f :: OpticKind -> OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Functor f =>
f a -> (a -> b) -> f b
<&> \v
v' -> Key -> v -> IntMap v -> IntMap v
forall (a :: OpticKind). Key -> a -> IntMap a -> IntMap a
IntMap.insert Key
k' v
v' IntMap v
s
{-# INLINE lt #-}

-- | Focus on the smallest key greater than the given one and its corresponding
-- value.
--
-- >>> IntMap.fromList [(1, "hi"), (2, "there")] & over (gt 2) (++ "!")
-- fromList [(1,"hi"),(2,"there")]
--
-- >>> ipreview (gt 1) $ IntMap.fromList [(1, 'x'), (2, 'y')]
-- Just (2,'y')
gt :: Int -> IxAffineTraversal' Int (IntMap v) v
gt :: Key -> IxAffineTraversal' Key (IntMap v) v
gt Key
k = IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (i :: OpticKind) (s :: OpticKind) (t :: OpticKind)
       (a :: OpticKind) (b :: OpticKind).
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL (IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
 -> IxAffineTraversal' Key (IntMap v) v)
-> IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ \forall (r :: OpticKind). r -> f r
point Key -> v -> f v
f IntMap v
s ->
  case Key -> IntMap v -> Maybe (Key, v)
forall (a :: OpticKind). Key -> IntMap a -> Maybe (Key, a)
IntMap.lookupGT Key
k IntMap v
s of
    Maybe (Key, v)
Nothing      -> IntMap v -> f (IntMap v)
forall (r :: OpticKind). r -> f r
point IntMap v
s
    Just (Key
k', v
v) -> Key -> v -> f v
f Key
k' v
v f v -> (v -> IntMap v) -> f (IntMap v)
forall (f :: OpticKind -> OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Functor f =>
f a -> (a -> b) -> f b
<&> \v
v' -> Key -> v -> IntMap v -> IntMap v
forall (a :: OpticKind). Key -> a -> IntMap a -> IntMap a
IntMap.insert Key
k' v
v' IntMap v
s
{-# INLINE gt #-}

-- | Focus on the largest key smaller or equal than the given one and its
-- corresponding value.
--
-- >>> IntMap.fromList [(1, "hi"), (2, "there")] & over (le 2) (++ "!")
-- fromList [(1,"hi"),(2,"there!")]
--
-- >>> ipreview (le 1) $ IntMap.fromList [(1, 'x'), (2, 'y')]
-- Just (1,'x')
le :: Int -> IxAffineTraversal' Int (IntMap v) v
le :: Key -> IxAffineTraversal' Key (IntMap v) v
le Key
k = IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (i :: OpticKind) (s :: OpticKind) (t :: OpticKind)
       (a :: OpticKind) (b :: OpticKind).
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL (IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
 -> IxAffineTraversal' Key (IntMap v) v)
-> IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ \forall (r :: OpticKind). r -> f r
point Key -> v -> f v
f IntMap v
s ->
  case Key -> IntMap v -> Maybe (Key, v)
forall (a :: OpticKind). Key -> IntMap a -> Maybe (Key, a)
IntMap.lookupLE Key
k IntMap v
s of
    Maybe (Key, v)
Nothing      -> IntMap v -> f (IntMap v)
forall (r :: OpticKind). r -> f r
point IntMap v
s
    Just (Key
k', v
v) -> Key -> v -> f v
f Key
k' v
v f v -> (v -> IntMap v) -> f (IntMap v)
forall (f :: OpticKind -> OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Functor f =>
f a -> (a -> b) -> f b
<&> \v
v' -> Key -> v -> IntMap v -> IntMap v
forall (a :: OpticKind). Key -> a -> IntMap a -> IntMap a
IntMap.insert Key
k' v
v' IntMap v
s
{-# INLINE le #-}

-- | Focus on the smallest key greater or equal than the given one and its
-- corresponding value.
--
-- >>> IntMap.fromList [(1, "hi"), (3, "there")] & over (ge 2) (++ "!")
-- fromList [(1,"hi"),(3,"there!")]
--
-- >>> ipreview (ge 2) $ IntMap.fromList [(1, 'x'), (3, 'y')]
-- Just (3,'y')
ge :: Int -> IxAffineTraversal' Int (IntMap v) v
ge :: Key -> IxAffineTraversal' Key (IntMap v) v
ge Key
k = IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (i :: OpticKind) (s :: OpticKind) (t :: OpticKind)
       (a :: OpticKind) (b :: OpticKind).
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL (IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
 -> IxAffineTraversal' Key (IntMap v) v)
-> IxAffineTraversalVL Key (IntMap v) (IntMap v) v v
-> IxAffineTraversal' Key (IntMap v) v
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ \forall (r :: OpticKind). r -> f r
point Key -> v -> f v
f IntMap v
s ->
  case Key -> IntMap v -> Maybe (Key, v)
forall (a :: OpticKind). Key -> IntMap a -> Maybe (Key, a)
IntMap.lookupGE Key
k IntMap v
s of
    Maybe (Key, v)
Nothing      -> IntMap v -> f (IntMap v)
forall (r :: OpticKind). r -> f r
point IntMap v
s
    Just (Key
k', v
v) -> Key -> v -> f v
f Key
k' v
v f v -> (v -> IntMap v) -> f (IntMap v)
forall (f :: OpticKind -> OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Functor f =>
f a -> (a -> b) -> f b
<&> \v
v' -> Key -> v -> IntMap v -> IntMap v
forall (a :: OpticKind). Key -> a -> IntMap a -> IntMap a
IntMap.insert Key
k' v
v' IntMap v
s
{-# INLINE ge #-}

-- $setup
-- >>> import Data.Monoid
-- >>> import Optics.Core