diff --git a/Cargo.toml b/Cargo.toml index 1c4ee89..8760ecd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,8 +56,15 @@ chrono = { version = "0.4.*", default-features = false, features = [ serde = { version = "1.*", default-features = false, features = [ "std", "derive", -] } -serde_json = { version = "1.*", default-features = false, features = ["std"] } +], optional = true } +serde_json = { version = "1.*", default-features = false, features = [ + "std", +], optional = true } + +[features] +default = [] +serde = ["dep:serde"] +serde-tags = ["dep:serde", "dep:serde_json"] [workspace] resolver = "2" diff --git a/src/lib.rs b/src/lib.rs index 8b43f90..3426ace 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,7 @@ use std::{ use aws_config::retry::RetryConfig; use aws_sdk_ec2::client::Waiters; use chrono::{DateTime, Utc}; +#[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; mod error; @@ -40,6 +41,7 @@ macro_rules! wrap_aws_enum { } } + #[cfg(feature = "serde")] impl Serialize for $name { fn serialize(&self, serializer: S) -> Result where @@ -49,6 +51,7 @@ macro_rules! wrap_aws_enum { } } + #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for $name { fn deserialize(deserializer: D) -> Result where @@ -196,11 +199,12 @@ impl Instance { } } -#[derive(Serialize, Deserialize, Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub enum Region { - #[serde(rename = "eu-central-1")] + #[cfg_attr(feature = "serde", serde(rename = "eu-central-1"))] EuCentral1, - #[serde(rename = "us-east-1")] + #[cfg_attr(feature = "serde", serde(rename = "us-east-1"))] UsEast1, } @@ -269,7 +273,8 @@ pub struct RegionClient { pub cdn: RegionClientCdn, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct InstanceProfileName(String); impl InstanceProfileName { @@ -278,7 +283,8 @@ impl InstanceProfileName { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct InstanceKeypairName(String); impl InstanceKeypairName { @@ -287,7 +293,8 @@ impl InstanceKeypairName { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct SecurityGroupId(String); impl SecurityGroupId { @@ -296,12 +303,14 @@ impl SecurityGroupId { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct SecurityGroup { id: SecurityGroupId, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct SubnetId(String); impl SubnetId { @@ -328,8 +337,9 @@ impl fmt::Display for SubnetId { macro_rules! string_newtype { ($name:ident) => { - #[Tag(translate = serde)] - #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq)] + #[Tag(translate = transparent)] + #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] + #[derive(Debug, Clone, Eq, PartialEq)] pub struct $name(String); impl std::fmt::Display for $name { @@ -342,7 +352,8 @@ macro_rules! string_newtype { string_newtype!(AvailabilityZone); -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct Subnet { pub id: SubnetId, pub availability_zone: AvailabilityZone, @@ -383,7 +394,8 @@ impl AmiId { } } -#[derive(Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug)] pub struct Ami { pub id: AmiId, pub tags: TagList, @@ -411,7 +423,8 @@ impl TryFrom for Ami { } #[Tag(translate = manual)] -#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] pub struct Timestamp(DateTime); impl Timestamp { @@ -468,7 +481,8 @@ impl TryFrom for Timestamp { } } -#[derive(Debug, Serialize, Deserialize, Clone)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct Ip(net::IpAddr); impl Ip { @@ -499,7 +513,8 @@ impl EipAllocationId { } } -#[derive(Debug, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug)] pub struct Eip { pub allocation_id: EipAllocationId, pub ip: Ip, @@ -568,8 +583,9 @@ impl Eip { string_newtype!(CloudfrontDistributionId); -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] +#[cfg_attr(feature = "serde", serde(rename_all = "lowercase"))] pub enum CloudfrontDistributionStatus { Deployed, Other(String), @@ -597,10 +613,12 @@ impl From for CloudfrontDistributionStatus { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct EfsId(String); -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct Efs { id: EfsId, region: Region, @@ -633,7 +651,8 @@ impl From for CloudfrontDistributionDomain { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct CloudfrontOrigin { id: CloudfrontOriginId, domain: CloudfrontOriginDomain, @@ -679,7 +698,8 @@ impl From for CloudfrontOrigin { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct CloudfrontDistribution { pub id: CloudfrontDistributionId, pub status: CloudfrontDistributionStatus, @@ -793,7 +813,8 @@ pub async fn load_sdk_clients( region_clients } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct Account { id: String, } @@ -808,7 +829,8 @@ impl Account { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct HostedZoneId(String); impl HostedZoneId { @@ -821,7 +843,8 @@ impl HostedZoneId { } } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[derive(Debug, Clone)] pub struct Route53Zone { hosted_zone_id: HostedZoneId, name: String, diff --git a/src/tags/README.md b/src/tags/README.md index 8af09cf..188f896 100644 --- a/src/tags/README.md +++ b/src/tags/README.md @@ -56,14 +56,10 @@ in a struct that is using `#[Tags]`: ```rust use aws_lib::tags::{Tag, Tags}; -use serde::{Serialize, Deserialize}; -#[Tag(translate = serde)] -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -struct MyTag { - foo: String, - bar: bool, -} +#[Tag(translate = transparent)] +#[derive(Debug, Clone, PartialEq, Eq)] +struct MyTag(String); #[Tags] struct MyTags { diff --git a/src/tags/mod.rs b/src/tags/mod.rs index f871ad2..a6f558d 100644 --- a/src/tags/mod.rs +++ b/src/tags/mod.rs @@ -1,7 +1,12 @@ #![doc = include_str!("README.md")] use std::fmt::{self, Debug}; -use serde::{de::DeserializeOwned, Deserialize, Serialize}; +#[cfg(feature = "serde-tags")] +use serde::de::DeserializeOwned; +#[cfg(feature = "serde")] +use serde::Deserialize; +#[cfg(any(feature = "serde-tags", feature = "serde"))] +use serde::Serialize; mod error; mod helpers; @@ -43,10 +48,12 @@ where } } -#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] pub struct RawTagValue(String); helpers::impl_string_wrapper!(RawTagValue); +#[cfg(feature = "serde-tags")] pub struct TranslateSerde; pub struct TranslateManual; @@ -57,6 +64,7 @@ pub trait Translator { fn into_raw_tag(value: T) -> RawTagValue; } +#[cfg(feature = "serde-tags")] pub trait TranslatableSerde: Serialize + DeserializeOwned {} pub trait TranslatableManual: TryFrom> + Into @@ -76,6 +84,7 @@ pub trait TagValue { } } +#[cfg(feature = "serde-tags")] impl Translator for TranslateSerde where T: TranslatableSerde, @@ -118,7 +127,8 @@ where } } -#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RawTag { key: TagKey, value: RawTagValue, @@ -155,7 +165,8 @@ where } } -#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Debug, PartialEq, Eq, Clone)] pub struct TagKey(String); helpers::impl_string_wrapper!(TagKey); @@ -252,7 +263,8 @@ where } } -#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)] +#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct TagList(Vec); impl TagList { @@ -292,6 +304,7 @@ impl TagList { #[cfg(test)] mod tests { + #[cfg(feature = "serde-tags")] use serde::{Deserialize, Serialize}; use super::*; @@ -303,6 +316,7 @@ mod tests { B, } + #[cfg(feature = "serde-tags")] #[Tag(translate = serde)] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] struct MyStructTag { @@ -358,7 +372,9 @@ mod tests { #[tag(key = "anothername")] tag6: Option, tag7: Option, + #[cfg(feature = "serde-tags")] tag8: MyStructTag, + #[cfg(feature = "serde-tags")] tag9: Option, } @@ -368,6 +384,7 @@ mod tests { RawTag::new("tag3".to_owned(), "false".to_owned()), RawTag::new("myname".to_owned(), "A".to_owned()), RawTag::new("anothername".to_owned(), "B".to_owned()), + #[cfg(feature = "serde-tags")] RawTag::new("tag8".to_owned(), r#"{"foo":"hi","bar":false}"#.to_owned()), ]); @@ -380,6 +397,7 @@ mod tests { assert!(tags.tag5 == MyTag::A); assert!(tags.tag6 == Some(MyTag::B)); assert!(tags.tag7.is_none()); + #[cfg(feature = "serde-tags")] assert!( tags.tag8 == MyStructTag { @@ -387,6 +405,7 @@ mod tests { bar: false } ); + #[cfg(feature = "serde-tags")] assert!(tags.tag9.is_none()); let into_tags = tags.into_tags(); @@ -399,6 +418,7 @@ mod tests { RawTag::new("tag3".to_owned(), "false".to_owned()), RawTag::new("myname".to_owned(), "A".to_owned()), RawTag::new("anothername".to_owned(), "B".to_owned()), + #[cfg(feature = "serde-tags")] RawTag::new("tag8".to_owned(), r#"{"foo":"hi","bar":false}"#.to_owned(),), ]) ); @@ -407,7 +427,7 @@ mod tests { #[test] fn test_transparent_tag() { #[Tag(translate = transparent)] - #[derive(Serialize, Deserialize, PartialEq, Debug)] + #[derive(PartialEq, Debug)] struct MyTag(String); assert_eq!( diff --git a/src/tags/predefined_types.rs b/src/tags/predefined_types.rs index b1907b6..43938d6 100644 --- a/src/tags/predefined_types.rs +++ b/src/tags/predefined_types.rs @@ -1,14 +1,35 @@ -use super::{ - ParseTagValueError, TagValue, TranslatableManual, TranslatableSerde, TranslateManual, - TranslateSerde, -}; +use super::{ParseTagValueError, RawTagValue, TagValue, TranslatableManual, TranslateManual}; -// Bools can just be handled by serde. -impl TranslatableSerde for bool {} +impl TranslatableManual for bool {} + +const TRUE_STR: &str = "true"; +const FALSE_STR: &str = "false"; impl TagValue for bool { type Error = ParseTagValueError; - type Translator = TranslateSerde; + type Translator = TranslateManual; +} + +impl TryFrom for bool { + type Error = ParseTagValueError; + + fn try_from(value: RawTagValue) -> Result { + match value.as_str() { + TRUE_STR => Ok(true), + FALSE_STR => Ok(false), + _ => Err(ParseTagValueError::InvalidBoolValue { value }), + } + } +} + +impl From for RawTagValue { + fn from(value: bool) -> Self { + if value { + Self::new(TRUE_STR.to_owned()) + } else { + Self::new(FALSE_STR.to_owned()) + } + } } // Due to quoting, we cannot use serde here. It would produce quoted