Skip to main content

fakecloud_aws/
arn.rs

1use std::fmt;
2
3/// An Amazon Resource Name.
4///
5/// Format: `arn:partition:service:region:account-id:resource`
6#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub struct Arn {
8    pub partition: String,
9    pub service: String,
10    pub region: String,
11    pub account_id: String,
12    pub resource: String,
13}
14
15impl Arn {
16    pub fn new(service: &str, region: &str, account_id: &str, resource: &str) -> Self {
17        Self {
18            partition: "aws".to_string(),
19            service: service.to_string(),
20            region: region.to_string(),
21            account_id: account_id.to_string(),
22            resource: resource.to_string(),
23        }
24    }
25
26    /// Create an ARN with no region (global services like IAM).
27    pub fn global(service: &str, account_id: &str, resource: &str) -> Self {
28        Self::new(service, "", account_id, resource)
29    }
30}
31
32impl fmt::Display for Arn {
33    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34        write!(
35            f,
36            "arn:{}:{}:{}:{}:{}",
37            self.partition, self.service, self.region, self.account_id, self.resource
38        )
39    }
40}
41
42impl std::str::FromStr for Arn {
43    type Err = ArnParseError;
44
45    fn from_str(s: &str) -> Result<Self, Self::Err> {
46        let parts: Vec<&str> = s.splitn(6, ':').collect();
47        if parts.len() != 6 || parts[0] != "arn" {
48            return Err(ArnParseError(s.to_string()));
49        }
50        Ok(Self {
51            partition: parts[1].to_string(),
52            service: parts[2].to_string(),
53            region: parts[3].to_string(),
54            account_id: parts[4].to_string(),
55            resource: parts[5].to_string(),
56        })
57    }
58}
59
60#[derive(Debug, thiserror::Error)]
61#[error("invalid ARN: {0}")]
62pub struct ArnParseError(String);
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn round_trip() {
70        let arn = Arn::new("sqs", "us-east-1", "123456789012", "my-queue");
71        let s = arn.to_string();
72        assert_eq!(s, "arn:aws:sqs:us-east-1:123456789012:my-queue");
73        assert_eq!(s.parse::<Arn>().unwrap(), arn);
74    }
75
76    #[test]
77    fn global_arn() {
78        let arn = Arn::global("iam", "123456789012", "user/admin");
79        assert_eq!(arn.to_string(), "arn:aws:iam::123456789012:user/admin");
80    }
81}