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;