From a909de1d21e8b4b56566e737e802d2c14f8dd6a7 Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Wed, 16 Nov 2022 00:48:21 +0800 Subject: [PATCH 1/8] Fixed warnings related to PartialEq & Eq --- src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 59ba964..d2c8ee3 100644 --- a/src/error.rs +++ b/src/error.rs @@ -4,7 +4,7 @@ use std::{error::Error as StdError, fmt}; /// Types of errors that may result from failed attempts /// to deserialize a type from env vars -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub enum Error { MissingValue(String), Custom(String), From d5a53447543016374ea2357f479e55f26292a37a Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Wed, 16 Nov 2022 11:20:59 +0800 Subject: [PATCH 2/8] WIP: Fixing auto conversion of field names --- src/lib.rs | 67 ++++++++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fd59d0a..840dc46 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -306,10 +306,7 @@ where T: de::DeserializeOwned, Iter: IntoIterator, { - T::deserialize(Deserializer::new(iter.into_iter())).map_err(|error| match error { - Error::MissingValue(value) => Error::MissingValue(value.to_uppercase()), - _ => error, - }) + T::deserialize(Deserializer::new(iter.into_iter())) } /// A type which filters env vars with a prefix for use as serde field inputs @@ -344,7 +341,7 @@ impl<'a> Prefixed<'a> { })) .map_err(|error| match error { Error::MissingValue(value) => Error::MissingValue( - format!("{prefix}{value}", prefix = self.0, value = value).to_uppercase(), + format!("{prefix}{value}", prefix = self.0, value = value), ), _ => error, }) @@ -427,14 +424,14 @@ mod tests { #[test] fn deserialize_from_iter() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("true")), - (String::from("DOOM"), String::from("1, 2, 3 ")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("true")), + (String::from("doom"), String::from("1, 2, 3 ")), // Empty string should result in empty vector. - (String::from("BOOM"), String::from("")), - (String::from("SIZE"), String::from("small")), - (String::from("PROVIDED"), String::from("test")), - (String::from("NEWTYPE"), String::from("42")), + (String::from("boom"), String::from("")), + (String::from("size"), String::from("small")), + (String::from("provided"), String::from("test")), + (String::from("newtype"), String::from("42")), ]; match from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( @@ -459,40 +456,40 @@ mod tests { #[test] fn fails_with_missing_value() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("true")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("true")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("doom".into())), } } #[test] fn prefixed_fails_with_missing_value() { let data = vec![ - (String::from("PREFIX_BAR"), String::from("test")), - (String::from("PREFIX_BAZ"), String::from("true")), + (String::from("prefix_bar"), String::from("test")), + (String::from("prefix_baz"), String::from("true")), ]; - match prefixed("PREFIX_").from_iter::<_, Foo>(data) { + match prefixed("prefix_").from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("PREFIX_DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("prefix_doom".into())), } } #[test] fn fails_with_invalid_type() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("notabool")), - (String::from("DOOM"), String::from("1,2,3")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("notabool")), + (String::from("doom"), String::from("1,2,3")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), Err(e) => assert_eq!( e, - Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by BAZ")) + Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by baz")) ), } } @@ -500,15 +497,15 @@ mod tests { #[test] fn deserializes_from_prefixed_fieldnames() { let data = vec![ - (String::from("APP_BAR"), String::from("test")), - (String::from("APP_BAZ"), String::from("true")), - (String::from("APP_DOOM"), String::from("")), - (String::from("APP_BOOM"), String::from("4,5")), - (String::from("APP_SIZE"), String::from("small")), - (String::from("APP_PROVIDED"), String::from("test")), - (String::from("APP_NEWTYPE"), String::from("42")), + (String::from("app_bar"), String::from("test")), + (String::from("app_baz"), String::from("true")), + (String::from("app_doom"), String::from("")), + (String::from("app_boom"), String::from("4,5")), + (String::from("app_size"), String::from("small")), + (String::from("app_provided"), String::from("test")), + (String::from("app_newtype"), String::from("42")), ]; - match prefixed("APP_").from_iter::<_, Foo>(data) { + match prefixed("app_").from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( actual, Foo { @@ -533,7 +530,7 @@ mod tests { let mut expected = HashMap::new(); expected.insert("foo".to_string(), "bar".to_string()); assert_eq!( - prefixed("PRE_").from_iter(vec![("PRE_FOO".to_string(), "bar".to_string())]), + prefixed("pre_").from_iter(vec![("pre_foo".to_string(), "bar".to_string())]), Ok(expected) ); } @@ -543,9 +540,9 @@ mod tests { let mut expected = HashMap::new(); expected.insert("foo".to_string(), 12); assert_eq!( - prefixed("PRE_").from_iter(vec![ - ("FOO".to_string(), "asd".to_string()), - ("PRE_FOO".to_string(), "12".to_string()) + prefixed("pre_").from_iter(vec![ + ("foo".to_string(), "asd".to_string()), + ("pre_foo".to_string(), "12".to_string()) ]), Ok(expected) ); From e6c64e67af82b4dc28eef5fdb4c1d31c3b61bdcc Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Wed, 16 Nov 2022 17:55:54 +0800 Subject: [PATCH 3/8] Added some fixes --- src/lib.rs | 51 ++++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 840dc46..f12ee26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,7 +105,7 @@ impl> Iterator for Vars { fn next(&mut self) -> Option { self.0 .next() - .map(|(k, v)| (VarName(k.to_lowercase()), Val(k, v))) + .map(|(k, v)| (VarName(k.clone()), Val(k, v))) } } @@ -405,6 +405,7 @@ mod tests { pub struct CustomNewType(u32); #[derive(Deserialize, Debug, PartialEq)] + #[serde(rename_all="SCREAMING_SNAKE_CASE")] pub struct Foo { bar: String, baz: bool, @@ -424,14 +425,14 @@ mod tests { #[test] fn deserialize_from_iter() { let data = vec![ - (String::from("bar"), String::from("test")), - (String::from("baz"), String::from("true")), - (String::from("doom"), String::from("1, 2, 3 ")), + (String::from("BAR"), String::from("test")), + (String::from("BAZ"), String::from("true")), + (String::from("DOOM"), String::from("1, 2, 3 ")), // Empty string should result in empty vector. - (String::from("boom"), String::from("")), - (String::from("size"), String::from("small")), - (String::from("provided"), String::from("test")), - (String::from("newtype"), String::from("42")), + (String::from("BOOM"), String::from("")), + (String::from("SIZE"), String::from("small")), + (String::from("PROVIDED"), String::from("test")), + (String::from("NEWTYPE"), String::from("42")), ]; match from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( @@ -456,40 +457,40 @@ mod tests { #[test] fn fails_with_missing_value() { let data = vec![ - (String::from("bar"), String::from("test")), - (String::from("baz"), String::from("true")), + (String::from("BAR"), String::from("test")), + (String::from("BAZ"), String::from("true")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("doom".into())), + Err(e) => assert_eq!(e, Error::MissingValue("DOOM".into())), } } #[test] fn prefixed_fails_with_missing_value() { let data = vec![ - (String::from("prefix_bar"), String::from("test")), - (String::from("prefix_baz"), String::from("true")), + (String::from("prefix_BAR"), String::from("test")), + (String::from("prefix_BAZ"), String::from("true")), ]; match prefixed("prefix_").from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("prefix_doom".into())), + Err(e) => assert_eq!(e, Error::MissingValue("prefix_DOOM".into())), } } #[test] fn fails_with_invalid_type() { let data = vec![ - (String::from("bar"), String::from("test")), - (String::from("baz"), String::from("notabool")), - (String::from("doom"), String::from("1,2,3")), + (String::from("BAR"), String::from("test")), + (String::from("BAZ"), String::from("notabool")), + (String::from("DOOM"), String::from("1,2,3")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), Err(e) => assert_eq!( e, - Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by baz")) + Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by BAZ")) ), } } @@ -497,13 +498,13 @@ mod tests { #[test] fn deserializes_from_prefixed_fieldnames() { let data = vec![ - (String::from("app_bar"), String::from("test")), - (String::from("app_baz"), String::from("true")), - (String::from("app_doom"), String::from("")), - (String::from("app_boom"), String::from("4,5")), - (String::from("app_size"), String::from("small")), - (String::from("app_provided"), String::from("test")), - (String::from("app_newtype"), String::from("42")), + (String::from("app_BAR"), String::from("test")), + (String::from("app_BAZ"), String::from("true")), + (String::from("app_DOOM"), String::from("")), + (String::from("app_BOOM"), String::from("4,5")), + (String::from("app_SIZE"), String::from("small")), + (String::from("app_PROVIDED"), String::from("test")), + (String::from("app_NEWTYPE"), String::from("42")), ]; match prefixed("app_").from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( From 8adac49565190c406fd17579d197091b23507ef2 Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Wed, 16 Nov 2022 17:57:00 +0800 Subject: [PATCH 4/8] Upgraded with new version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 312ceaf..48b9e20 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "envy" -version = "0.4.2" +version = "0.4.3" authors = ["softprops "] description = "deserialize env vars into typesafe structs" documentation = "https://softprops.github.io/envy" From d200bcced2deba6103f0739fad7f79af7406bafb Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Wed, 16 Nov 2022 22:53:17 +0800 Subject: [PATCH 5/8] restored some changes --- src/lib.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index f12ee26..79f4fbb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -469,13 +469,13 @@ mod tests { #[test] fn prefixed_fails_with_missing_value() { let data = vec![ - (String::from("prefix_BAR"), String::from("test")), - (String::from("prefix_BAZ"), String::from("true")), + (String::from("PREFIX_BAR"), String::from("test")), + (String::from("PREFIX_BAZ"), String::from("true")), ]; - match prefixed("prefix_").from_iter::<_, Foo>(data) { + match prefixed("PREFIX_").from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("prefix_DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("PREFIX_DOOM".into())), } } @@ -498,15 +498,15 @@ mod tests { #[test] fn deserializes_from_prefixed_fieldnames() { let data = vec![ - (String::from("app_BAR"), String::from("test")), - (String::from("app_BAZ"), String::from("true")), - (String::from("app_DOOM"), String::from("")), - (String::from("app_BOOM"), String::from("4,5")), - (String::from("app_SIZE"), String::from("small")), - (String::from("app_PROVIDED"), String::from("test")), - (String::from("app_NEWTYPE"), String::from("42")), + (String::from("APP_BAR"), String::from("test")), + (String::from("APP_BAZ"), String::from("true")), + (String::from("APP_DOOM"), String::from("")), + (String::from("APP_BOOM"), String::from("4,5")), + (String::from("APP_SIZE"), String::from("small")), + (String::from("APP_PROVIDED"), String::from("test")), + (String::from("APP_NEWTYPE"), String::from("42")), ]; - match prefixed("app_").from_iter::<_, Foo>(data) { + match prefixed("APP_").from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( actual, Foo { @@ -531,7 +531,7 @@ mod tests { let mut expected = HashMap::new(); expected.insert("foo".to_string(), "bar".to_string()); assert_eq!( - prefixed("pre_").from_iter(vec![("pre_foo".to_string(), "bar".to_string())]), + prefixed("PRE_").from_iter(vec![("PRE_foo".to_string(), "bar".to_string())]), Ok(expected) ); } @@ -541,9 +541,9 @@ mod tests { let mut expected = HashMap::new(); expected.insert("foo".to_string(), 12); assert_eq!( - prefixed("pre_").from_iter(vec![ + prefixed("PRE_").from_iter(vec![ ("foo".to_string(), "asd".to_string()), - ("pre_foo".to_string(), "12".to_string()) + ("PRE_foo".to_string(), "12".to_string()) ]), Ok(expected) ); From 3f41d46e986dc95c2ede55042a1b71c44a0304f4 Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Thu, 17 Nov 2022 10:03:40 +0800 Subject: [PATCH 6/8] Refined changes to minimize --- src/lib.rs | 88 +++++++++++++++++++++++++++++++++++------------------- 1 file changed, 57 insertions(+), 31 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 79f4fbb..e13fb3b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,9 +103,7 @@ impl> Iterator for Vars { type Item = (VarName, Val); fn next(&mut self) -> Option { - self.0 - .next() - .map(|(k, v)| (VarName(k.clone()), Val(k, v))) + self.0.next().map(|(k, v)| (VarName(k.clone()), Val(k, v))) } } @@ -340,9 +338,9 @@ impl<'a> Prefixed<'a> { } })) .map_err(|error| match error { - Error::MissingValue(value) => Error::MissingValue( - format!("{prefix}{value}", prefix = self.0, value = value), - ), + Error::MissingValue(value) => { + Error::MissingValue(format!("{prefix}{value}", prefix = self.0, value = value)) + } _ => error, }) } @@ -405,7 +403,6 @@ mod tests { pub struct CustomNewType(u32); #[derive(Deserialize, Debug, PartialEq)] - #[serde(rename_all="SCREAMING_SNAKE_CASE")] pub struct Foo { bar: String, baz: bool, @@ -425,14 +422,14 @@ mod tests { #[test] fn deserialize_from_iter() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("true")), - (String::from("DOOM"), String::from("1, 2, 3 ")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("true")), + (String::from("doom"), String::from("1, 2, 3 ")), // Empty string should result in empty vector. - (String::from("BOOM"), String::from("")), - (String::from("SIZE"), String::from("small")), - (String::from("PROVIDED"), String::from("test")), - (String::from("NEWTYPE"), String::from("42")), + (String::from("boom"), String::from("")), + (String::from("size"), String::from("small")), + (String::from("provided"), String::from("test")), + (String::from("newtype"), String::from("42")), ]; match from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( @@ -457,40 +454,40 @@ mod tests { #[test] fn fails_with_missing_value() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("true")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("true")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("doom".into())), } } #[test] fn prefixed_fails_with_missing_value() { let data = vec![ - (String::from("PREFIX_BAR"), String::from("test")), - (String::from("PREFIX_BAZ"), String::from("true")), + (String::from("PREFIX_bar"), String::from("test")), + (String::from("PREFIX_baz"), String::from("true")), ]; match prefixed("PREFIX_").from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), - Err(e) => assert_eq!(e, Error::MissingValue("PREFIX_DOOM".into())), + Err(e) => assert_eq!(e, Error::MissingValue("PREFIX_doom".into())), } } #[test] fn fails_with_invalid_type() { let data = vec![ - (String::from("BAR"), String::from("test")), - (String::from("BAZ"), String::from("notabool")), - (String::from("DOOM"), String::from("1,2,3")), + (String::from("bar"), String::from("test")), + (String::from("baz"), String::from("notabool")), + (String::from("doom"), String::from("1,2,3")), ]; match from_iter::<_, Foo>(data) { Ok(_) => panic!("expected failure"), Err(e) => assert_eq!( e, - Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by BAZ")) + Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by baz")) ), } } @@ -498,13 +495,13 @@ mod tests { #[test] fn deserializes_from_prefixed_fieldnames() { let data = vec![ - (String::from("APP_BAR"), String::from("test")), - (String::from("APP_BAZ"), String::from("true")), - (String::from("APP_DOOM"), String::from("")), - (String::from("APP_BOOM"), String::from("4,5")), - (String::from("APP_SIZE"), String::from("small")), - (String::from("APP_PROVIDED"), String::from("test")), - (String::from("APP_NEWTYPE"), String::from("42")), + (String::from("APP_bar"), String::from("test")), + (String::from("APP_baz"), String::from("true")), + (String::from("APP_doom"), String::from("")), + (String::from("APP_boom"), String::from("4,5")), + (String::from("APP_size"), String::from("small")), + (String::from("APP_provided"), String::from("test")), + (String::from("APP_newtype"), String::from("42")), ]; match prefixed("APP_").from_iter::<_, Foo>(data) { Ok(actual) => assert_eq!( @@ -548,4 +545,33 @@ mod tests { Ok(expected) ); } + + #[test] + fn deserialize_rename_field() { + #[derive(Deserialize, Debug, PartialEq)] + #[serde(rename_all = "SCREAMING_SNAKE_CASE")] + pub struct FooRename { + bar: String, + bar_snake: String, + #[serde(rename = "FooRename")] + foo: String, + } + + let data = vec![ + (String::from("BAR"), String::from("dummy string 1")), + (String::from("BAR_SNAKE"), String::from("dummy string 2")), + (String::from("FooRename"), String::from("dummy string 3")), + ]; + match from_iter::<_, FooRename>(data) { + Ok(actual) => assert_eq!( + actual, + FooRename { + bar: String::from("dummy string 1"), + bar_snake: String::from("dummy string 2"), + foo: String::from("dummy string 3"), + } + ), + Err(e) => panic!("{:#?}", e), + } + } } From 5506cfbbe6c0af1350882e59475f423b6138f65a Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Thu, 17 Nov 2022 10:12:14 +0800 Subject: [PATCH 7/8] Put cargo.toml back --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 48b9e20..312ceaf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "envy" -version = "0.4.3" +version = "0.4.2" authors = ["softprops "] description = "deserialize env vars into typesafe structs" documentation = "https://softprops.github.io/envy" From 8d33690d1ebb5d69f0e38e4bf7370e35e3fe44a2 Mon Sep 17 00:00:00 2001 From: haiying2080 Date: Thu, 17 Nov 2022 10:13:37 +0800 Subject: [PATCH 8/8] Renamed unit-test function name --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e13fb3b..83181cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -547,7 +547,7 @@ mod tests { } #[test] - fn deserialize_rename_field() { + fn deserialize_with_rename_attributes() { #[derive(Deserialize, Debug, PartialEq)] #[serde(rename_all = "SCREAMING_SNAKE_CASE")] pub struct FooRename {