{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UnicodeSyntax #-}

-- |
-- Module: Configuration.Utils.Monoid
-- Description: Configuration of Monoids
-- Copyright: Copyright © 2015 PivotCloud, Inc.
-- License: MIT
-- Maintainer: Lars Kuhtz <lkuhtz@pivotmail.com>
-- Stability: experimental
--
-- The distinction between appending on the left and appending on the right is
-- important for monoids that are sensitive to ordering such as 'List'. It is
-- also of relevance for monoids with set semantics with non-extensional
-- equality such as `HashMap`.
--
module Configuration.Utils.Monoid
  ( LeftMonoidalUpdate
  , leftMonoidalUpdate
  , fromLeftMonoidalUpdate
  , pLeftMonoidalUpdate
  , pLeftSemigroupalUpdate
  , RightMonoidalUpdate
  , rightMonoidalUpdate
  , fromRightMonoidalUpdate
  , pRightMonoidalUpdate
  , pRightSemigroupalUpdate
  ) where

import Configuration.Utils.CommandLine
import Configuration.Utils.Internal

import Data.Aeson
import qualified Data.List.NonEmpty as NEL
import Data.Semigroup
import Data.Semigroup.Foldable (fold1)

import qualified Options.Applicative.Types as O

import Prelude hiding (any, concatMap, mapM_)
import Prelude.Unicode

-- | Update a value by appending on the left. Under normal
-- circumstances you'll never use this type directly but only
-- its 'FromJSON' instance. See the 'leftMonoidalUpdate' for an example.
--
newtype LeftMonoidalUpdate a = LeftMonoidalUpdate
    { forall a. LeftMonoidalUpdate a -> a
_getLeftMonoidalUpdate  a
    }
    deriving (NonEmpty (LeftMonoidalUpdate a) -> LeftMonoidalUpdate a
LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
forall b.
Integral b =>
b -> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
forall a.
Semigroup a =>
NonEmpty (LeftMonoidalUpdate a) -> LeftMonoidalUpdate a
forall a.
Semigroup a =>
LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
forall a b.
(Semigroup a, Integral b) =>
b -> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b.
Integral b =>
b -> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
$cstimes :: forall a b.
(Semigroup a, Integral b) =>
b -> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
sconcat :: NonEmpty (LeftMonoidalUpdate a) -> LeftMonoidalUpdate a
$csconcat :: forall a.
Semigroup a =>
NonEmpty (LeftMonoidalUpdate a) -> LeftMonoidalUpdate a
<> :: LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
$c<> :: forall a.
Semigroup a =>
LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
Semigroup, LeftMonoidalUpdate a
[LeftMonoidalUpdate a] -> LeftMonoidalUpdate a
LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
forall {a}. Monoid a => Semigroup (LeftMonoidalUpdate a)
forall a. Monoid a => LeftMonoidalUpdate a
forall a.
Monoid a =>
[LeftMonoidalUpdate a] -> LeftMonoidalUpdate a
forall a.
Monoid a =>
LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
mconcat :: [LeftMonoidalUpdate a] -> LeftMonoidalUpdate a
$cmconcat :: forall a.
Monoid a =>
[LeftMonoidalUpdate a] -> LeftMonoidalUpdate a
mappend :: LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
$cmappend :: forall a.
Monoid a =>
LeftMonoidalUpdate a
-> LeftMonoidalUpdate a -> LeftMonoidalUpdate a
mempty :: LeftMonoidalUpdate a
$cmempty :: forall a. Monoid a => LeftMonoidalUpdate a
Monoid)

-- | Update a value by appending on the left.
--
-- > newtype RoutingTable = RoutingTable { _routingTableMap ∷ HashMap T.Text T.Text }
-- >
-- > $(makeLenses ''RoutingTable)
-- >
-- > instance FromJSON (RoutingTable → RoutingTable) where
-- >     parseJSON = withObject "RoutingTable" $ \o → id
-- >         <$< routingTableMap . from leftMonoidalUpdate %.: "route_map" % o
--
leftMonoidalUpdate  Iso (LeftMonoidalUpdate a) (LeftMonoidalUpdate b) a b
leftMonoidalUpdate :: forall a b. Iso (LeftMonoidalUpdate a) (LeftMonoidalUpdate b) a b
leftMonoidalUpdate = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall a. LeftMonoidalUpdate a -> a
_getLeftMonoidalUpdate forall a. a -> LeftMonoidalUpdate a
LeftMonoidalUpdate

-- | This is the same as @from leftMonoidalUpdate@ but doesn't depend on
-- the lens Library.
--
fromLeftMonoidalUpdate  Iso a b (LeftMonoidalUpdate a) (LeftMonoidalUpdate b)
fromLeftMonoidalUpdate :: forall a b. Iso a b (LeftMonoidalUpdate a) (LeftMonoidalUpdate b)
fromLeftMonoidalUpdate = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall a. a -> LeftMonoidalUpdate a
LeftMonoidalUpdate forall a. LeftMonoidalUpdate a -> a
_getLeftMonoidalUpdate

instance (FromJSON a, Monoid a)  FromJSON (LeftMonoidalUpdate a  LeftMonoidalUpdate a) where
    parseJSON :: Value -> Parser (LeftMonoidalUpdate a -> LeftMonoidalUpdate a)
parseJSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a. Monoid a => a -> a -> a
mappend forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. a -> LeftMonoidalUpdate a
LeftMonoidalUpdate) forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. FromJSON a => Value -> Parser a
parseJSON

-- | Update a value by appending on the left.
--
-- > newtype RoutingTable = RoutingTable { _routingTableMap ∷ HashMap T.Text T.Text }
-- >
-- > $(makeLenses ''RoutingTable)
-- >
-- > pRoutingTable ∷ MParser RoutingTable
-- > pRoutingTable = routingTableMap %:: pLeftMonoidalUpdate pRoute
-- >   where
-- >     pRoute = option (eitherReader readRoute)
-- >         % long "route"
-- >         <> help "add a route to the routing table; the APIROUTE part must not contain a colon character"
-- >         <> metavar "APIROUTE:APIURL"
-- >
-- >     readRoute s = case break (== ':') s of
-- >         (a,':':b) → first T.unpack $ do
-- >             validateNonEmpty "APIROUTE" a
-- >             validateHttpOrHttpsUrl "APIURL" b
-- >             return $ HM.singleton (T.pack a) (T.pack b)
-- >         _ → Left "missing colon between APIROUTE and APIURL"
-- >
-- >     first f = either (Left . f) Right
--
pLeftMonoidalUpdate  Monoid a  O.Parser a  MParser a
pLeftMonoidalUpdate :: forall a. Monoid a => Parser a -> MParser a
pLeftMonoidalUpdate Parser a
pElement = forall a. Monoid a => a -> a -> a
mappend forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. Monoid a => [a] -> a
mconcat forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. [a] -> [a]
reverse forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser a
pElement

-- | Like `pLeftMonoidalUpdate`, but works for `Semigroup`s instead. Using this
-- parser requires the input to have at least one copy (say, for flags that can
-- be passed multiple times).
--
pLeftSemigroupalUpdate  Semigroup a  O.Parser a  MParser a
pLeftSemigroupalUpdate :: forall a. Semigroup a => Parser a -> MParser a
pLeftSemigroupalUpdate Parser a
pElement = forall a. Semigroup a => a -> a -> a
(<>) forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall (t :: * -> *) m. (Foldable1 t, Semigroup m) => t m -> m
fold1 forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. [a] -> NonEmpty a
NEL.fromList forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. [a] -> [a]
reverse forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f [a]
some Parser a
pElement

-- | Update a value by appending on the right. Under normal
-- circumstances you'll never use this type directly but only
-- its 'FromJSON' instance. See the 'leftMonoidalUpdate' for an example.
--
newtype RightMonoidalUpdate a = RightMonoidalUpdate
    { forall a. RightMonoidalUpdate a -> a
_getRightMonoidalUpdate  a
    }
    deriving (NonEmpty (RightMonoidalUpdate a) -> RightMonoidalUpdate a
RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
forall b.
Integral b =>
b -> RightMonoidalUpdate a -> RightMonoidalUpdate a
forall a.
Semigroup a =>
NonEmpty (RightMonoidalUpdate a) -> RightMonoidalUpdate a
forall a.
Semigroup a =>
RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
forall a b.
(Semigroup a, Integral b) =>
b -> RightMonoidalUpdate a -> RightMonoidalUpdate a
forall a.
(a -> a -> a)
-> (NonEmpty a -> a)
-> (forall b. Integral b => b -> a -> a)
-> Semigroup a
stimes :: forall b.
Integral b =>
b -> RightMonoidalUpdate a -> RightMonoidalUpdate a
$cstimes :: forall a b.
(Semigroup a, Integral b) =>
b -> RightMonoidalUpdate a -> RightMonoidalUpdate a
sconcat :: NonEmpty (RightMonoidalUpdate a) -> RightMonoidalUpdate a
$csconcat :: forall a.
Semigroup a =>
NonEmpty (RightMonoidalUpdate a) -> RightMonoidalUpdate a
<> :: RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
$c<> :: forall a.
Semigroup a =>
RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
Semigroup, RightMonoidalUpdate a
[RightMonoidalUpdate a] -> RightMonoidalUpdate a
RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
forall a.
Semigroup a -> a -> (a -> a -> a) -> ([a] -> a) -> Monoid a
forall {a}. Monoid a => Semigroup (RightMonoidalUpdate a)
forall a. Monoid a => RightMonoidalUpdate a
forall a.
Monoid a =>
[RightMonoidalUpdate a] -> RightMonoidalUpdate a
forall a.
Monoid a =>
RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
mconcat :: [RightMonoidalUpdate a] -> RightMonoidalUpdate a
$cmconcat :: forall a.
Monoid a =>
[RightMonoidalUpdate a] -> RightMonoidalUpdate a
mappend :: RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
$cmappend :: forall a.
Monoid a =>
RightMonoidalUpdate a
-> RightMonoidalUpdate a -> RightMonoidalUpdate a
mempty :: RightMonoidalUpdate a
$cmempty :: forall a. Monoid a => RightMonoidalUpdate a
Monoid)

-- | Update a value by appending on the right. See 'leftMonoidalUpdate' for
-- an usage example.
--
rightMonoidalUpdate  Iso (RightMonoidalUpdate a) (RightMonoidalUpdate b) a b
rightMonoidalUpdate :: forall a b. Iso (RightMonoidalUpdate a) (RightMonoidalUpdate b) a b
rightMonoidalUpdate = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall a. RightMonoidalUpdate a -> a
_getRightMonoidalUpdate forall a. a -> RightMonoidalUpdate a
RightMonoidalUpdate

-- | This is the same as @from rightMonoidalUpdate@ but doesn't depend on
-- the lens Library.
--
fromRightMonoidalUpdate  Iso a b (RightMonoidalUpdate a) (RightMonoidalUpdate b)
fromRightMonoidalUpdate :: forall a b. Iso a b (RightMonoidalUpdate a) (RightMonoidalUpdate b)
fromRightMonoidalUpdate = forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso forall a. a -> RightMonoidalUpdate a
RightMonoidalUpdate forall a. RightMonoidalUpdate a -> a
_getRightMonoidalUpdate

instance (FromJSON a, Monoid a)  FromJSON (RightMonoidalUpdate a  RightMonoidalUpdate a) where
    parseJSON :: Value -> Parser (RightMonoidalUpdate a -> RightMonoidalUpdate a)
parseJSON = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Monoid a => a -> a -> a
mappend forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. a -> RightMonoidalUpdate a
RightMonoidalUpdate) forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. FromJSON a => Value -> Parser a
parseJSON

-- | Update a value by appending on the right. See 'pLeftMonoidalUpdate'
-- for an usage example.
--
pRightMonoidalUpdate  Monoid a  O.Parser a  MParser a
pRightMonoidalUpdate :: forall a. Monoid a => Parser a -> MParser a
pRightMonoidalUpdate Parser a
pElement = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Monoid a => a -> a -> a
mappend forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. Monoid a => [a] -> a
mconcat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f [a]
many Parser a
pElement

-- | Like `pRightMonoidalUpdate`, but works for `Semigroup`s instead. Using this
-- parser requires the input to have at least one copy (say, for flags that can
-- be passed multiple times).
--
pRightSemigroupalUpdate  Semigroup a  O.Parser a  MParser a
pRightSemigroupalUpdate :: forall a. Semigroup a => Parser a -> MParser a
pRightSemigroupalUpdate Parser a
pElement = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. Semigroup a => a -> a -> a
(<>) forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall (t :: * -> *) m. (Foldable1 t, Semigroup m) => t m -> m
fold1 forall β γ α. (β -> γ) -> (α -> β) -> α -> γ
 forall a. [a] -> NonEmpty a
NEL.fromList forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (f :: * -> *) a. Alternative f => f a -> f [a]
some Parser a
pElement