aws_arn/builder/
mod.rs

1/*!
2* Provides a more natural builder interface for constructing ResourceNames.
3*
4* The builder pattern allows for a more readable construction of ResourceNames, and in this case we
5* provide a number of *verb* prefixes on *noun* constructors, so we have `in_region` as well as
6* `and_region` which is more readable if it is preceded by `in_partition`. For the account id
7* field there is `in_account`, `and_account`, `any_account`, and `owned_by`; all of these
8* accomplish the same goal but allow for a choice that makes code easir to understand.
9*
10* # Resource-Specific Constructor Functions
11*
12* For the service-specific submodules (`iam`, `lambda`, `s3`, etc.) the functions are simply named
13* for the noun that represents the resource type as described in the AWS documentation. As the
14* partition in commonly left to default to "aws" there are also a set of `{noun}_in()` functions
15* that take a partition, and corresponding `{noun}()` functions which do not.
16*
17* In some cases where an ResourceName may be dependent on another, for example an S3 object ResourceName might be
18* constructed from an existing bucket ResourceName, additional `{noun}_from(other,...)` functions will
19* be provided.
20*
21* Note that the final `build()` function will call `validate()`, and so it is possible to call
22* intermediate functions with bad data which is only caught at build time.
23*
24* # Example
25*
26* The following shows the construction of an AWS versioned layer ResourceName.
27*
28* ```rust
29* use aws_arn::builder::{ArnBuilder, ResourceBuilder};
30* use aws_arn::{
31*     AccountIdentifier, Identifier, IdentifierLike, ResourceIdentifier, ResourceName
32* };
33* use aws_arn::known::{Region, Service};
34* use std::str::FromStr;
35*
36* let arn: ResourceName = ArnBuilder::service_id(Service::Lambda.into())
37*     .resource(
38*         ResourceBuilder::typed(Identifier::new_unchecked("layer"))
39*             .resource_name(Identifier::new_unchecked("my-layer"))
40*             .version(3)
41*             .build_qualified_id(),
42*     )
43*     .in_region_id(Region::UsEast2.into())
44*     .owned_by(AccountIdentifier::from_str("123456789012").unwrap())
45*     .into();
46* println!("ResourceName: '{}'", arn);
47* ```
48*
49* This should print `ResourceName: 'arn:aws:lambda:us-east-2:123456789012:layer:my-layer:3'`.
50*/
51
52use crate::known::{Partition, Region, Service};
53use crate::{AccountIdentifier, Identifier, IdentifierLike, ResourceIdentifier, ResourceName};
54
55// ------------------------------------------------------------------------------------------------
56// Public Types
57// ------------------------------------------------------------------------------------------------
58
59///
60/// Builder type for an AWS `ResourceName`.
61///
62#[derive(Clone, Debug)]
63pub struct ArnBuilder {
64    arn: ResourceName,
65}
66
67///
68/// Builder type for a `ResourceIdentifier`.
69///
70/// The methods `build_resource_path` and `build_qualified_id` are used to construct identifiers
71/// with either the '/' or ':' separator between the collected components.
72///
73#[derive(Clone, Debug, Default)]
74pub struct ResourceBuilder {
75    resource: Vec<ResourceIdentifier>,
76}
77
78// ------------------------------------------------------------------------------------------------
79// Implementations
80// ------------------------------------------------------------------------------------------------
81
82impl From<ArnBuilder> for ResourceName {
83    fn from(v: ArnBuilder) -> Self {
84        v.arn
85    }
86}
87
88impl From<&mut ArnBuilder> for ResourceName {
89    fn from(v: &mut ArnBuilder) -> Self {
90        v.arn.clone()
91    }
92}
93
94impl ArnBuilder {
95    /// Construct an ResourceName for the specified `service`.
96    pub fn service(service: Service) -> Self {
97        Self::service_id(service.into())
98    }
99
100    /// Construct an ResourceName for the specified `service`.
101    pub fn service_id(service: Identifier) -> Self {
102        Self {
103            arn: ResourceName {
104                partition: None,
105                service,
106                region: None,
107                account_id: None,
108                resource: ResourceIdentifier::default(),
109            },
110        }
111    }
112
113    /// Set a specific `partition` for this ResourceName.
114    pub fn in_partition(&mut self, partition: Partition) -> &mut Self {
115        self.in_partition_id(partition.into())
116    }
117
118    /// Set a specific `partition` for this ResourceName.
119    pub fn in_partition_id(&mut self, partition: Identifier) -> &mut Self {
120        self.arn.partition = Some(partition);
121        self
122    }
123
124    /// Set a specific `partition` for this ResourceName.
125    pub fn in_default_partition(&mut self) -> &mut Self {
126        self.arn.partition = Some(Partition::default().into());
127        self
128    }
129
130    /// Set a specific `partition` for this ResourceName.
131    pub fn in_any_partition(&mut self) -> &mut Self {
132        self.arn.partition = None;
133        self
134    }
135
136    /// Set a specific `region` for this ResourceName.
137    pub fn in_region(&mut self, region: Region) -> &mut Self {
138        self.in_region_id(region.into())
139    }
140
141    /// Set a specific `region` for this ResourceName.
142    pub fn in_region_id(&mut self, region: Identifier) -> &mut Self {
143        self.arn.region = Some(region);
144        self
145    }
146
147    /// Set a specific `region` for this ResourceName.
148    pub fn and_region(&mut self, region: Region) -> &mut Self {
149        self.in_region_id(region.into())
150    }
151
152    /// Set a specific `region` for this ResourceName.
153    pub fn and_region_id(&mut self, region: Identifier) -> &mut Self {
154        self.in_region_id(region)
155    }
156
157    /// Set `region` to a wildcard for this ResourceName.
158    pub fn in_any_region(&mut self) -> &mut Self {
159        self.in_region_id(Identifier::default())
160    }
161
162    /// Set a specific `account` for this ResourceName.
163    pub fn in_account(&mut self, account: AccountIdentifier) -> &mut Self {
164        self.arn.account_id = Some(account);
165        self
166    }
167
168    /// Set a specific `account` for this ResourceName.
169    pub fn and_account(&mut self, account: AccountIdentifier) -> &mut Self {
170        self.in_account(account)
171    }
172
173    /// Set a specific `account` for this ResourceName.
174    pub fn owned_by(&mut self, account: AccountIdentifier) -> &mut Self {
175        self.in_account(account)
176    }
177
178    /// Set `account` to a wildcard for this ResourceName.
179    pub fn in_any_account(&mut self) -> &mut Self {
180        self.in_account(AccountIdentifier::default())
181    }
182
183    /// Set a specific `resource` for this ResourceName.
184    pub fn resource(&mut self, resource: ResourceIdentifier) -> &mut Self {
185        self.arn.resource = resource;
186        self
187    }
188
189    /// Set a specific `resource` for this ResourceName.
190    pub fn is(&mut self, resource: ResourceIdentifier) -> &mut Self {
191        self.resource(resource)
192    }
193
194    /// Set a specific `resource` for this ResourceName.
195    pub fn a(&mut self, resource: ResourceIdentifier) -> &mut Self {
196        self.resource(resource)
197    }
198
199    /// Set `resource` to a wildcard for this ResourceName.
200    pub fn any_resource(&mut self) -> &mut Self {
201        self.arn.resource = ResourceIdentifier::any();
202        self
203    }
204
205    /// Set `resource` to a wildcard for this ResourceName.
206    pub fn for_any_resource(&mut self) -> &mut Self {
207        self.any_resource()
208    }
209}
210
211// ------------------------------------------------------------------------------------------------
212
213impl From<ResourceIdentifier> for ResourceBuilder {
214    fn from(v: ResourceIdentifier) -> Self {
215        Self { resource: vec![v] }
216    }
217}
218
219impl From<Identifier> for ResourceBuilder {
220    fn from(v: Identifier) -> Self {
221        Self {
222            resource: vec![v.into()],
223        }
224    }
225}
226
227impl ResourceBuilder {
228    /// Construct a new resource builder containing only the provided identifier.
229    pub fn named(id: Identifier) -> Self {
230        Self {
231            resource: vec![id.into()],
232        }
233    }
234
235    /// Construct a new resource builder containing only the provided identifier.
236    pub fn typed(id: Identifier) -> Self {
237        Self {
238            resource: vec![id.into()],
239        }
240    }
241
242    /// Add the provided `ResourceIdentifier` to the inner list of components.
243    pub fn add(&mut self, id: ResourceIdentifier) -> &mut Self {
244        self.resource.push(id);
245        self
246    }
247
248    /// Add the provided `ResourceIdentifier` to the inner list of components.
249    pub fn qualified_name(&mut self, id: ResourceIdentifier) -> &mut Self {
250        self.resource.push(id);
251        self
252    }
253
254    /// Add the provided `ResourceIdentifier` to the inner list of components.
255    pub fn resource_path(&mut self, id: ResourceIdentifier) -> &mut Self {
256        self.resource.push(id);
257        self
258    }
259
260    /// Add the provided `Identifier` to the inner list of components.
261    pub fn type_name(&mut self, id: Identifier) -> &mut Self {
262        self.resource.push(id.into());
263        self
264    }
265
266    /// Add the provided `Identifier` to the inner list of components.
267    pub fn resource_name(&mut self, id: Identifier) -> &mut Self {
268        self.resource.push(id.into());
269        self
270    }
271
272    /// Add the provided `Identifier` to the inner list of components.
273    pub fn sub_resource_name(&mut self, id: Identifier) -> &mut Self {
274        self.resource.push(id.into());
275        self
276    }
277
278    /// Add the provided integer version number to the inner list of components.
279    pub fn version(&mut self, v: u32) -> &mut Self {
280        self.resource
281            .push(Identifier::new_unchecked(&v.to_string()).into());
282        self
283    }
284
285    /// Return the iner list of components as a resource identifier path.
286    pub fn build_resource_path(&mut self) -> ResourceIdentifier {
287        ResourceIdentifier::from_path(&self.resource)
288    }
289
290    /// Return the iner list of components as a qualified resource identifier.
291    pub fn build_qualified_id(&mut self) -> ResourceIdentifier {
292        ResourceIdentifier::from_qualified(&self.resource)
293    }
294}
295
296// ------------------------------------------------------------------------------------------------
297// Modules
298// ------------------------------------------------------------------------------------------------
299
300pub mod cognito;
301
302pub mod iam;
303
304pub mod lambda;
305
306pub mod s3;