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

-- |
--
-- Module      : Network.AWS.ARN
-- Copyright   : (C) 2020-2021 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:
--
-- @
-- -- 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' . 'arnResource' . 'slashes') (\\parts -> take 2 parts ++ ["*"]) authorizerSampleARN
-- @
module Network.AWS.ARN
  ( ARN (..),
    toARN,
    fromARN,

    -- * ARN Optics
    _ARN,
    arnPartition,
    arnService,
    arnRegion,
    arnAccount,
    arnResource,

    -- * Utility Optics
    colons,
    slashes,
  )
where

import Control.Lens (Iso', Prism', iso, makeLenses, prism')
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 Text.Show.Deriving (deriveShow1)

-- $setup
-- >>> :set -XOverloadedStrings
-- >>> import Control.Lens

-- | A parsed ARN. Either use the '_ARN' 'Prism'', or the 'toARN' and
-- 'fromARN' functions to convert @'Text' \<-\> 'ARN'@.  The
-- '_arnResource' 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' @'Control.Lens.Iso''@s in this module can pick apart the
-- `_arnResource` field.
--
-- == 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 . arnResource . Lambda._Function . Lambda.fName
-- @
--
-- 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)
-- @
data ARN r = ARN
  { ARN r -> Text
_arnPartition :: Text,
    ARN r -> Text
_arnService :: Text,
    ARN r -> Text
_arnRegion :: Text,
    ARN r -> Text
_arnAccount :: Text,
    ARN r -> r
_arnResource :: r
  }
  deriving
    ( ARN r -> ARN r -> Bool
(ARN r -> ARN r -> Bool) -> (ARN r -> ARN r -> Bool) -> Eq (ARN r)
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,
      Eq (ARN r)
Eq (ARN r)
-> (ARN r -> ARN r -> Ordering)
-> (ARN r -> ARN r -> Bool)
-> (ARN r -> ARN r -> Bool)
-> (ARN r -> ARN r -> Bool)
-> (ARN r -> ARN r -> Bool)
-> (ARN r -> ARN r -> ARN r)
-> (ARN r -> ARN r -> ARN r)
-> Ord (ARN r)
ARN r -> ARN r -> Bool
ARN r -> ARN r -> Ordering
ARN r -> ARN r -> ARN r
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
$cp1Ord :: forall r. Ord r => Eq (ARN r)
Ord,
      Int -> ARN r -> ShowS
[ARN r] -> ShowS
ARN r -> String
(Int -> ARN r -> ShowS)
-> (ARN r -> String) -> ([ARN r] -> ShowS) -> Show (ARN r)
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 x. ARN r -> Rep (ARN r) x)
-> (forall x. Rep (ARN r) x -> ARN r) -> Generic (ARN r)
forall x. Rep (ARN r) x -> ARN r
forall x. ARN r -> Rep (ARN r) x
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. ARN a -> Rep1 ARN a)
-> (forall a. Rep1 ARN a -> ARN a) -> Generic1 ARN
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,
      Int -> ARN r -> Int
ARN r -> Int
(Int -> ARN r -> Int) -> (ARN r -> Int) -> Hashable (ARN r)
forall r. Hashable r => Int -> ARN r -> Int
forall r. Hashable r => ARN r -> Int
forall a. (Int -> a -> Int) -> (a -> Int) -> Hashable a
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. (Int -> a -> Int) -> Int -> ARN a -> Int)
-> Hashable1 ARN
forall a. (Int -> a -> Int) -> Int -> ARN a -> Int
forall (t :: * -> *).
(forall a. (Int -> a -> Int) -> Int -> t a -> Int) -> Hashable1 t
liftHashWithSalt :: (Int -> a -> Int) -> Int -> ARN a -> Int
$cliftHashWithSalt :: forall a. (Int -> a -> Int) -> Int -> ARN a -> Int
Hashable1,
      a -> ARN b -> ARN a
(a -> b) -> ARN a -> ARN b
(forall a b. (a -> b) -> ARN a -> ARN b)
-> (forall a b. a -> ARN b -> ARN a) -> Functor ARN
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
<$ :: a -> ARN b -> ARN a
$c<$ :: forall a b. a -> ARN b -> ARN a
fmap :: (a -> b) -> ARN a -> ARN b
$cfmap :: forall a b. (a -> b) -> ARN a -> ARN b
Functor,
      ARN a -> Bool
(a -> m) -> ARN a -> m
(a -> b -> b) -> b -> ARN a -> b
(forall m. Monoid m => ARN m -> m)
-> (forall m a. Monoid m => (a -> m) -> ARN a -> m)
-> (forall m a. Monoid m => (a -> m) -> ARN a -> m)
-> (forall a b. (a -> b -> b) -> b -> ARN a -> b)
-> (forall a b. (a -> b -> b) -> b -> ARN a -> b)
-> (forall b a. (b -> a -> b) -> b -> ARN a -> b)
-> (forall b a. (b -> a -> b) -> b -> ARN a -> b)
-> (forall a. (a -> a -> a) -> ARN a -> a)
-> (forall a. (a -> a -> a) -> ARN a -> a)
-> (forall a. ARN a -> [a])
-> (forall a. ARN a -> Bool)
-> (forall a. ARN a -> Int)
-> (forall a. Eq a => a -> ARN a -> Bool)
-> (forall a. Ord a => ARN a -> a)
-> (forall a. Ord a => ARN a -> a)
-> (forall a. Num a => ARN a -> a)
-> (forall a. Num a => ARN a -> a)
-> Foldable ARN
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 :: ARN a -> a
$cproduct :: forall a. Num a => ARN a -> a
sum :: ARN a -> a
$csum :: forall a. Num a => ARN a -> a
minimum :: ARN a -> a
$cminimum :: forall a. Ord a => ARN a -> a
maximum :: ARN a -> a
$cmaximum :: forall a. Ord a => ARN a -> a
elem :: a -> ARN a -> Bool
$celem :: forall a. Eq a => a -> ARN a -> Bool
length :: ARN a -> Int
$clength :: forall a. ARN a -> Int
null :: ARN a -> Bool
$cnull :: forall a. ARN a -> Bool
toList :: ARN a -> [a]
$ctoList :: forall a. ARN a -> [a]
foldl1 :: (a -> a -> a) -> ARN a -> a
$cfoldl1 :: forall a. (a -> a -> a) -> ARN a -> a
foldr1 :: (a -> a -> a) -> ARN a -> a
$cfoldr1 :: forall a. (a -> a -> a) -> ARN a -> a
foldl' :: (b -> a -> b) -> b -> ARN a -> b
$cfoldl' :: forall b a. (b -> a -> b) -> b -> ARN a -> b
foldl :: (b -> a -> b) -> b -> ARN a -> b
$cfoldl :: forall b a. (b -> a -> b) -> b -> ARN a -> b
foldr' :: (a -> b -> b) -> b -> ARN a -> b
$cfoldr' :: forall a b. (a -> b -> b) -> b -> ARN a -> b
foldr :: (a -> b -> b) -> b -> ARN a -> b
$cfoldr :: forall a b. (a -> b -> b) -> b -> ARN a -> b
foldMap' :: (a -> m) -> ARN a -> m
$cfoldMap' :: forall m a. Monoid m => (a -> m) -> ARN a -> m
foldMap :: (a -> m) -> ARN a -> m
$cfoldMap :: forall m a. Monoid m => (a -> m) -> ARN a -> m
fold :: ARN m -> m
$cfold :: forall m. Monoid m => ARN m -> m
Foldable,
      Functor ARN
Foldable ARN
Functor ARN
-> Foldable ARN
-> (forall (f :: * -> *) a b.
    Applicative f =>
    (a -> f b) -> ARN a -> f (ARN b))
-> (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 (m :: * -> *) a. Monad m => ARN (m a) -> m (ARN a))
-> Traversable ARN
(a -> f b) -> ARN a -> f (ARN b)
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 :: ARN (m a) -> m (ARN a)
$csequence :: forall (m :: * -> *) a. Monad m => ARN (m a) -> m (ARN a)
mapM :: (a -> m b) -> ARN a -> m (ARN b)
$cmapM :: forall (m :: * -> *) a b.
Monad m =>
(a -> m b) -> ARN a -> m (ARN b)
sequenceA :: ARN (f a) -> f (ARN a)
$csequenceA :: forall (f :: * -> *) a. Applicative f => ARN (f a) -> f (ARN a)
traverse :: (a -> f b) -> ARN a -> f (ARN b)
$ctraverse :: forall (f :: * -> *) a b.
Applicative f =>
(a -> f b) -> ARN a -> f (ARN b)
$cp2Traversable :: Foldable ARN
$cp1Traversable :: Functor ARN
Traversable
    )

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

toARN :: Text -> Maybe (ARN Text)
toARN :: Text -> Maybe (ARN Text)
toARN Text
t = case Text -> Text -> [Text]
T.splitOn Text
":" Text
t of
  (Text
"arn" : Text
part : Text
srv : Text
reg : Text
acc : [Text]
res) ->
    ARN Text -> Maybe (ARN Text)
forall a. a -> Maybe a
Just (ARN Text -> Maybe (ARN Text)) -> ARN Text -> Maybe (ARN Text)
forall a b. (a -> b) -> a -> b
$
      ARN :: forall r. Text -> Text -> Text -> Text -> r -> ARN r
ARN
        { _arnPartition :: Text
_arnPartition = Text
part,
          _arnService :: Text
_arnService = Text
srv,
          _arnRegion :: Text
_arnRegion = Text
reg,
          _arnAccount :: Text
_arnAccount = Text
acc,
          _arnResource :: Text
_arnResource = Text -> [Text] -> Text
T.intercalate Text
":" [Text]
res
        }
  [Text]
_ -> Maybe (ARN Text)
forall a. Maybe a
Nothing

fromARN :: ARN Text -> Text
fromARN :: ARN Text -> Text
fromARN ARN Text
arn =
  Text -> [Text] -> Text
T.intercalate
    Text
":"
    [ Text
"arn",
      ARN Text -> Text
forall r. ARN r -> Text
_arnPartition ARN Text
arn,
      ARN Text -> Text
forall r. ARN r -> Text
_arnService ARN Text
arn,
      ARN Text -> Text
forall r. ARN r -> Text
_arnRegion ARN Text
arn,
      ARN Text -> Text
forall r. ARN r -> Text
_arnAccount ARN Text
arn,
      ARN Text -> Text
forall r. ARN r -> r
_arnResource ARN Text
arn
    ]

_ARN :: Prism' Text (ARN Text)
_ARN :: p (ARN Text) (f (ARN Text)) -> p Text (f Text)
_ARN = (ARN Text -> Text)
-> (Text -> Maybe (ARN Text))
-> Prism Text Text (ARN Text) (ARN Text)
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' ARN Text -> Text
fromARN Text -> Maybe (ARN Text)
toARN
{-# INLINE _ARN #-}

-- | Split a 'Text' into colon-separated parts.
--
-- This is not truly a lawful 'Iso'', but it is useful. The 'Iso''
-- laws are violated for lists whose members contain @':'@:
--
-- >>> [":"] ^. from colons . colons
-- ["",""]
--
-- The laws are also violated on empty lists:
--
-- >>> [] ^. from colons . colons
-- [""]
--
-- However, it is still a useful tool:
--
-- >>> "foo:bar:baz" & colons . ix 1 .~ "quux"
-- "foo:quux:baz"
colons :: Iso' Text [Text]
colons :: p [Text] (f [Text]) -> p Text (f Text)
colons = (Text -> [Text]) -> ([Text] -> Text) -> Iso Text Text [Text] [Text]
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (Text -> Text -> [Text]
T.splitOn Text
":") (Text -> [Text] -> Text
T.intercalate Text
":")
{-# INLINE colons #-}

-- | Split a 'Text' into slash-separated parts.
--
-- This is not truly a lawful 'Iso'', but it is useful:
--
-- >>> "foo/bar/baz" ^. slashes
-- ["foo","bar","baz"]
--
-- Similar caveats to 'colons' apply here.
slashes :: Iso' Text [Text]
slashes :: p [Text] (f [Text]) -> p Text (f Text)
slashes = (Text -> [Text]) -> ([Text] -> Text) -> Iso Text Text [Text] [Text]
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (Text -> Text -> [Text]
T.splitOn Text
"/") (Text -> [Text] -> Text
T.intercalate Text
"/")
{-# INLINE slashes #-}