{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# OPTIONS_HADDOCK show-extensions #-}

-- |
--
-- Module      : Network.AWS.ARN
-- Copyright   : (C) 2020-2022 Bellroy Pty Ltd
-- License     : BSD-3-Clause
-- Maintainer  : Bellroy Tech Team <haskell@bellroy.com>
-- Stability   : experimental
--
-- Provides a type representing [Amazon Resource Names
-- (ARNs)](https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html),
-- and parsing/unparsing functions for them. The provided optics make it
-- very convenient to rewrite parts of ARNs.
--
-- == Example
--
-- [API Gateway Lambda
-- Authorizers](https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-use-lambda-authorizer.html)
-- are given the ARN of the requested endpoint and method, and are
-- expected to respond with an IAM Policy Document. It is sometimes
-- useful to manipulate the given ARN when describing which resources to
-- authorize.
--
-- Here, we generalize @authorizerSampleARN@ to cover every method of
-- every endpoint in the stage:
--
-- @
-- {-# LANGUAGE OverloadedLabels #-}
-- -- This provides the necessary instances from generic-lens
-- import Data.Generics.Labels ()
--
-- -- Returns "arn:aws:execute-api:us-east-1:123456789012:my-spiffy-api\/stage\/*"
-- let
--   authorizerSampleARN = "arn:aws:execute-api:us-east-1:123456789012:my-spiffy-api\/stage\/GET\/some\/deep\/path"
-- in
--   over ('_ARN' . #resource . 'slashes') (\\parts -> take 2 parts ++ ["*"]) authorizerSampleARN
-- @
module Network.AWS.ARN
  ( ARN (..),
    parseARN,
    renderARN,

    -- * ARN Prism
    _ARN,

    -- * Utility Optics
    colons,
    slashes,
  )
where

import Data.Eq.Deriving (deriveEq1)
import Data.Hashable (Hashable)
import Data.Hashable.Lifted (Hashable1)
import Data.Ord.Deriving (deriveOrd1)
import Data.Text (Text)
import qualified Data.Text as T
import GHC.Generics (Generic, Generic1)
import Network.AWS.ARN.Internal.Lens (Iso', Prism', iso, prism')
import Text.Show.Deriving (deriveShow1)

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Data.Function ((&))
-- >>> import Network.AWS.ARN.Internal.Lens (from, ix, (.~), (^.), (^?))

-- | A parsed ARN. Either use the '_ARN' 'Prism'', or the 'parseARN' and
-- 'renderARN' functions to convert @'Text' \<-\> 'ARN'@.  The
-- 'resource' part of an ARN will often contain colon- or
-- slash-separated parts which precisely identify some resource. If
-- there is no service-specific module (see below), the 'colons' and
-- 'slashes' optics in this module can pick apart the `resource`
-- field.
--
-- If you want lenses into individual fields, use the
-- [@generic-lens@](https://hackage.haskell.org/package/generic-lens)
-- or
-- [@generic-optics@](https://hackage.haskell.org/package/generic-optics)
-- libraries.
--
-- == Service-Specific Modules
--
-- Modules like "Network.AWS.ARN.Lambda" provide types to parse the
-- resource part of an ARN into something more specific:
--
-- @
-- -- Remark: Lambda._Function :: Prism' Text Lambda.Function
-- -- Returns: Just "the-coolest-function-ever"
-- let
--   functionARN = "arn:aws:lambda:us-east-1:123456789012:function:the-coolest-function-ever:Alias"
-- in
--   functionARN ^? _ARN . #resource . Lambda._Function . #name
-- @
--
-- You can also use 'ARN'\'s 'Traversable' instance and
-- 'Control.Lens.Prism.below' to create 'Prism''s that indicate their
-- resource type in 'ARN'\'s type variable:
--
-- @
-- '_ARN' . 'Control.Lens.Prism.below' Lambda._Function :: Prism' Text ('ARN' Lambda.Function)
-- @
--
-- @since 0.1.0.0
data ARN r = ARN
  { forall r. ARN r -> Text
partition :: Text,
    forall r. ARN r -> Text
service :: Text,
    forall r. ARN r -> Text
region :: Text,
    forall r. ARN r -> Text
account :: Text,
    forall r. ARN r -> r
resource :: r
  }
  deriving
    ( ARN r -> ARN r -> Bool
forall r. Eq r => ARN r -> ARN r -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: ARN r -> ARN r -> Bool
$c/= :: forall r. Eq r => ARN r -> ARN r -> Bool
== :: ARN r -> ARN r -> Bool
$c== :: forall r. Eq r => ARN r -> ARN r -> Bool
Eq,
      ARN r -> ARN r -> Bool
ARN r -> ARN r -> Ordering
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall {r}. Ord r => Eq (ARN r)
forall r. Ord r => ARN r -> ARN r -> Bool
forall r. Ord r => ARN r -> ARN r -> Ordering
forall r. Ord r => ARN r -> ARN r -> ARN r
min :: ARN r -> ARN r -> ARN r
$cmin :: forall r. Ord r => ARN r -> ARN r -> ARN r
max :: ARN r -> ARN r -> ARN r
$cmax :: forall r. Ord r => ARN r -> ARN r -> ARN r
>= :: ARN r -> ARN r -> Bool
$c>= :: forall r. Ord r => ARN r -> ARN r -> Bool
> :: ARN r -> ARN r -> Bool
$c> :: forall r. Ord r => ARN r -> ARN r -> Bool
<= :: ARN r -> ARN r -> Bool
$c<= :: forall r. Ord r => ARN r -> ARN r -> Bool
< :: ARN r -> ARN r -> Bool
$c< :: forall r. Ord r => ARN r -> ARN r -> Bool
compare :: ARN r -> ARN r -> Ordering
$ccompare :: forall r. Ord r => ARN r -> ARN r -> Ordering
Ord,
      Int -> ARN r -> ShowS
forall r. Show r => Int -> ARN r -> ShowS
forall r. Show r => [ARN r] -> ShowS
forall r. Show r => ARN r -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [ARN r] -> ShowS
$cshowList :: forall r. Show r => [ARN r] -> ShowS
show :: ARN r -> String
$cshow :: forall r. Show r => ARN r -> String
showsPrec :: Int -> ARN r -> ShowS
$cshowsPrec :: forall r. Show r => Int -> ARN r -> ShowS
Show,
      forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall r x. Rep (ARN r) x -> ARN r
forall r x. ARN r -> Rep (ARN r) x
$cto :: forall r x. Rep (ARN r) x -> ARN r
$cfrom :: forall r x. ARN r -> Rep (ARN r) x
Generic,
      forall a. Rep1 ARN a -> ARN a
forall a. ARN a -> Rep1 ARN a
forall k (f :: k -> *).
(forall (a :: k). f a -> Rep1 f a)
-> (forall (a :: k). Rep1 f a -> f a) -> Generic1 f
$cto1 :: forall a. Rep1 ARN a -> ARN a
$cfrom1 :: forall a. ARN a -> Rep1 ARN a
Generic1,
      forall a. Eq a -> (Int -> a -> Int) -> (a -> Int) -> Hashable a
forall {r}. Hashable r => Eq (ARN r)
forall r. Hashable r => Int -> ARN r -> Int
forall r. Hashable r => ARN r -> Int
hash :: ARN r -> Int
$chash :: forall r. Hashable r => ARN r -> Int
hashWithSalt :: Int -> ARN r -> Int
$chashWithSalt :: forall r. Hashable r => Int -> ARN r -> Int
Hashable,
      forall a b. a -> ARN b -> ARN a
forall a b. (a -> b) -> ARN a -> ARN b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> ARN b -> ARN a
$c<$ :: forall a b. a -> ARN b -> ARN a
fmap :: forall a b. (a -> b) -> ARN a -> ARN b
$cfmap :: forall a b. (a -> b) -> ARN a -> ARN b
Functor,
      forall a. Eq a => a -> ARN a -> Bool
forall a. Num a => ARN a -> a
forall a. Ord a => ARN a -> a
forall m. Monoid m => ARN m -> m
forall a. ARN a -> Bool
forall a. ARN a -> Int
forall a. ARN a -> [a]
forall a. (a -> a -> a) -> ARN a -> a
forall m a. Monoid m => (a -> m) -> ARN a -> m
forall b a. (b -> a -> b) -> b -> ARN a -> b
forall a b. (a -> b -> b) -> b -> ARN a -> b
forall (t :: * -> *).
(forall m. Monoid m => t m -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall m a. Monoid m => (a -> m) -> t a -> m)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall a b. (a -> b -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall b a. (b -> a -> b) -> b -> t a -> b)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. (a -> a -> a) -> t a -> a)
-> (forall a. t a -> [a])
-> (forall a. t a -> Bool)
-> (forall a. t a -> Int)
-> (forall a. Eq a => a -> t a -> Bool)
-> (forall a. Ord a => t a -> a)
-> (forall a. Ord a => t a -> a)
-> (forall a. Num a => t a -> a)
-> (forall a. Num a => t a -> a)
-> Foldable t
product :: forall a. Num a => ARN a -> a
$cproduct :: forall a. Num a => ARN a -> a
sum :: forall a. Num a => ARN a -> a
$csum :: forall a. Num a => ARN a -> a
minimum :: forall a. Ord a => ARN a -> a
$cminimum :: forall a. Ord a => ARN a -> a
maximum :: forall a. Ord a => ARN a -> a
$cmaximum :: forall a. Ord a => ARN a -> a
elem :: forall a. Eq a => a -> ARN a -> Bool
$celem :: forall a. Eq a => a -> ARN a -> Bool
length :: forall a. ARN a -> Int
$clength :: forall a. ARN a -> Int
null :: forall a. ARN a -> Bool
$cnull :: forall a. ARN a -> Bool
toList :: forall a. ARN a -> [a]
$ctoList :: forall a. ARN a -> [a]
foldl1 :: forall a. (a -> a -> a) -> ARN a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> ARN a -> a
foldr1 :: forall a. (a -> a -> a) -> ARN a -> a
$cfoldr1 :: forall a. (a -> a -> a) -> ARN a -> a
foldl' :: forall b a. (b -> a -> b) -> b -> ARN a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> ARN a -> b
foldl :: forall b a. (b -> a -> b) -> b -> ARN a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> ARN a -> b
foldr' :: forall a b. (a -> b -> b) -> b -> ARN a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> ARN a -> b
foldr :: forall a b. (a -> b -> b) -> b -> ARN a -> b
$cfoldr :: forall a b. (a -> b -> b) -> b -> ARN a -> b
foldMap' :: forall m a. Monoid m => (a -> m) -> ARN a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> ARN a -> m
foldMap :: forall m a. Monoid m => (a -> m) -> ARN a -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> ARN a -> m
fold :: forall m. Monoid m => ARN m -> m
$cfold :: forall m. Monoid m => ARN m -> m
Foldable,
      Functor ARN
Foldable ARN
forall (t :: * -> *).
Functor t
-> Foldable t
-> (forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> t a -> f (t b))
-> (forall (f :: * -> *) a. Applicative f => t (f a) -> f (t a))
-> (forall (m :: * -> *) a b.
    Monad m =>
    (a -> m b) -> t a -> m (t b))
-> (forall (m :: * -> *) a. Monad m => t (m a) -> m (t a))
-> Traversable t
forall (m :: * -> *) a. Monad m => ARN (m a) -> m (ARN a)
forall (f :: * -> *) a. Applicative f => ARN (f a) -> f (ARN a)
forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> ARN a -> m (ARN b)
forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> ARN a -> f (ARN b)
sequence :: forall (m :: * -> *) a. Monad m => ARN (m a) -> m (ARN a)
$csequence :: forall (m :: * -> *) a. Monad m => ARN (m a) -> m (ARN a)
mapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> ARN a -> m (ARN b)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> ARN a -> m (ARN b)
sequenceA :: forall (f :: * -> *) a. Applicative f => ARN (f a) -> f (ARN a)
$csequenceA :: forall (f :: * -> *) a. Applicative f => ARN (f a) -> f (ARN a)
traverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> ARN a -> f (ARN b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> ARN a -> f (ARN b)
Traversable
    )

$(deriveEq1 ''ARN)
$(deriveOrd1 ''ARN)
$(deriveShow1 ''ARN)

deriving instance Hashable1 ARN

-- | @since 0.2.0.0
parseARN :: Text -> Maybe (ARN Text)
parseARN :: Text -> Maybe (ARN Text)
parseARN Text
t = case Text -> Text -> [Text]
T.splitOn Text
":" Text
t of
  (Text
"arn" : Text
part : Text
srv : Text
reg : Text
acc : [Text]
res) ->
    forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$
      ARN
        { partition :: Text
partition = Text
part,
          service :: Text
service = Text
srv,
          region :: Text
region = Text
reg,
          account :: Text
account = Text
acc,
          resource :: Text
resource = Text -> [Text] -> Text
T.intercalate Text
":" [Text]
res
        }
  [Text]
_ -> forall a. Maybe a
Nothing

-- | @since 0.2.0.0
renderARN :: ARN Text -> Text
renderARN :: ARN Text -> Text
renderARN ARN Text
arn =
  Text -> [Text] -> Text
T.intercalate
    Text
":"
    [ Text
"arn",
      forall r. ARN r -> Text
partition ARN Text
arn,
      forall r. ARN r -> Text
service ARN Text
arn,
      forall r. ARN r -> Text
region ARN Text
arn,
      forall r. ARN r -> Text
account ARN Text
arn,
      forall r. ARN r -> r
resource ARN Text
arn
    ]

-- | @since 0.1.0.0
_ARN :: Prism' Text (ARN Text)
_ARN :: Prism' Text (ARN Text)
_ARN = forall s a. (a -> s) -> (s -> Maybe a) -> Prism' s a
prism' ARN Text -> Text
renderARN Text -> Maybe (ARN Text)
parseARN
{-# INLINE _ARN #-}

-- | Split a 'Text' into colon-separated parts.
--
-- This is an improper 'Iso'' (@Text.intercalate ":" . Text.splitOn
-- ":" = id@, but @Text.splitOn ":" . Text.intercalate ":" /= id@).
-- This causes violations of the 'Iso'' laws for lists whose members
-- contain @\':\'@:
--
-- >>> [":"] ^. from colons . colons
-- ["",""]
--
-- The laws are also violated on empty lists:
--
-- >>> [] ^. from colons . colons
-- [""]
--
-- Nevertheless, it is still useful:
--
-- >>> "foo:bar:baz" & colons . ix 1 .~ "quux"
-- "foo:quux:baz"
--
-- Ed [discusses improper
-- optics](https://old.reddit.com/r/haskell/comments/32xva8/the_laws_of_asymmetric_wellbehaved_lenses_are/cqhq1gk/)
-- in an old Reddit comment.
--
-- @since 0.3.0.0
colons :: Iso' Text [Text]
colons :: Iso' Text [Text]
colons = forall s a. (s -> a) -> (a -> s) -> Iso' s a
iso (Text -> Text -> [Text]
T.splitOn Text
":") (Text -> [Text] -> Text
T.intercalate Text
":")
{-# INLINE colons #-}

-- | Split a 'Text' into slash-separated parts.
--
-- List 'colons', this is an improper 'Iso'', but it is still useful:
--
-- >>> "foo/bar/baz" ^. slashes
-- ["foo","bar","baz"]
--
-- @since 0.3.0.0
slashes :: Iso' Text [Text]
slashes :: Iso' Text [Text]
slashes = forall s a. (s -> a) -> (a -> s) -> Iso' s a
iso (Text -> Text -> [Text]
T.splitOn Text
"/") (Text -> [Text] -> Text
T.intercalate Text
"/")
{-# INLINE slashes #-}