diff --git a/.github/workflows/build-events.yml b/.github/workflows/build-events.yml index dbf9a0ae..3a56e597 100644 --- a/.github/workflows/build-events.yml +++ b/.github/workflows/build-events.yml @@ -26,3 +26,12 @@ jobs: with: package: aws_lambda_events toolchain: ${{ matrix.toolchain}} + check-event-features: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - uses: Swatinem/rust-cache@v2 + + - name: Test individual event features + run: make check-event-features diff --git a/Makefile b/Makefile index cb00545c..544d08b7 100644 --- a/Makefile +++ b/Makefile @@ -60,3 +60,47 @@ invoke-integration-api-%: curl -X POST -d '{"command": "hello"}' $(API_URL)/trait/post curl -X POST -d '{"command": "hello"}' $(API_URL)/al2/post curl -X POST -d '{"command": "hello"}' $(API_URL)/al2-trait/post + +# Test individual event features to ensure optional dependencies +# are correctly loaded when all default features are disabled. +check-event-features: + cargo test --package aws_lambda_events --no-default-features --features activemq + cargo test --package aws_lambda_events --no-default-features --features alb + cargo test --package aws_lambda_events --no-default-features --features apigw + cargo test --package aws_lambda_events --no-default-features --features appsync + cargo test --package aws_lambda_events --no-default-features --features autoscaling + cargo test --package aws_lambda_events --no-default-features --features chime_bot + cargo test --package aws_lambda_events --no-default-features --features clientvpn + cargo test --package aws_lambda_events --no-default-features --features cloudwatch_events + cargo test --package aws_lambda_events --no-default-features --features cloudwatch_logs + cargo test --package aws_lambda_events --no-default-features --features code_commit + cargo test --package aws_lambda_events --no-default-features --features codebuild + cargo test --package aws_lambda_events --no-default-features --features codedeploy + cargo test --package aws_lambda_events --no-default-features --features codepipeline_cloudwatch + cargo test --package aws_lambda_events --no-default-features --features codepipeline_job + cargo test --package aws_lambda_events --no-default-features --features cognito + cargo test --package aws_lambda_events --no-default-features --features config + cargo test --package aws_lambda_events --no-default-features --features connect + cargo test --package aws_lambda_events --no-default-features --features dynamodb + cargo test --package aws_lambda_events --no-default-features --features ecr_scan + cargo test --package aws_lambda_events --no-default-features --features firehose + cargo test --package aws_lambda_events --no-default-features --features iam + cargo test --package aws_lambda_events --no-default-features --features iot + cargo test --package aws_lambda_events --no-default-features --features iot_1_click + cargo test --package aws_lambda_events --no-default-features --features iot_button + cargo test --package aws_lambda_events --no-default-features --features iot_deprecated + cargo test --package aws_lambda_events --no-default-features --features kafka + cargo test --package aws_lambda_events --no-default-features --features kinesis + cargo test --package aws_lambda_events --no-default-features --features kinesis_analytics + cargo test --package aws_lambda_events --no-default-features --features lambda_function_urls + cargo test --package aws_lambda_events --no-default-features --features lex + cargo test --package aws_lambda_events --no-default-features --features rabbitmq + cargo test --package aws_lambda_events --no-default-features --features s3 + cargo test --package aws_lambda_events --no-default-features --features s3_batch_job + cargo test --package aws_lambda_events --no-default-features --features ses + cargo test --package aws_lambda_events --no-default-features --features sns + cargo test --package aws_lambda_events --no-default-features --features sqs + cargo test --package aws_lambda_events --no-default-features --features streams + +fmt: + cargo +nightly fmt --all \ No newline at end of file diff --git a/lambda-events/Cargo.toml b/lambda-events/Cargo.toml index 57be6bde..b1108c63 100644 --- a/lambda-events/Cargo.toml +++ b/lambda-events/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws_lambda_events" -version = "0.9.0" +version = "0.10.0" description = "AWS Lambda event definitions" authors = [ "Christian Legnitto ", @@ -13,29 +13,26 @@ repository = "https://github.com/awslabs/aws-lambda-rust-runtime" readme = "README.md" keywords = ["lambda", "aws", "amazon", "events", "S3"] categories = ["api-bindings", "encoding", "web-programming"] +edition = "2021" [dependencies] base64 = "0.21" -http = "0.2" -http-body = "0.4" -http-serde = "^1" -serde = "^1" -serde_derive = "^1" +http = { version = "0.2", optional = true } +http-body = { version = "0.4", optional = true } +http-serde = { version = "^1", optional = true } +serde = { version = "^1", features = ["derive"] } serde_with = { version = "^3", features = ["json"], optional = true } serde_json = "^1" serde_dynamo = { version = "^4.1", optional = true } -bytes = { version = "1", features = ["serde"] } +bytes = { version = "1", features = ["serde"], optional = true } chrono = { version = "0.4.23", default-features = false, features = [ "clock", "serde", "std", -] } -query_map = { version = "^0.6", features = ["serde", "url-query"] } +], optional = true } +query_map = { version = "^0.6", features = ["serde", "url-query"], optional = true } flate2 = { version = "1.0.24", optional = true } -[dev-dependencies] -pretty_assertions = "1.3" - [features] default = [ "activemq", @@ -78,40 +75,40 @@ default = [ ] activemq = [] -alb = [] -apigw = [] +alb = ["bytes", "http", "http-body", "http-serde", "query_map"] +apigw = ["bytes", "http", "http-body", "http-serde", "query_map"] appsync = [] -autoscaling = [] -chime_bot = [] +autoscaling = ["chrono"] +chime_bot = ["chrono"] clientvpn = [] -cloudwatch_events = [] +cloudwatch_events = ["chrono"] cloudwatch_logs = ["flate2"] -code_commit = [] -codebuild = [] -codedeploy = [] +code_commit = ["chrono"] +codebuild = ["chrono"] +codedeploy = ["chrono"] codepipeline = [] -codepipeline_cloudwatch = [] +codepipeline_cloudwatch = ["chrono"] codepipeline_job = [] cognito = [] config = [] connect = [] -dynamodb = ["streams", "serde_dynamo"] +dynamodb = ["chrono", "serde_dynamo", "streams"] ecr_scan = [] -firehose = [] +firehose = ["chrono"] iam = [] -iot = ["iam"] +iot = ["bytes", "http", "http-body", "http-serde", "iam"] iot_1_click = [] iot_button = [] iot_deprecated = ["iot"] -kafka = [] -kinesis = [] +kafka = ["chrono"] +kinesis = ["chrono"] kinesis_analytics = ["kinesis"] -lambda_function_urls = [] +lambda_function_urls = ["bytes", "http", "http-body", "http-serde"] lex = [] rabbitmq = [] -s3 = [] +s3 = ["bytes", "chrono", "http", "http-body", "http-serde"] s3_batch_job = ["s3"] -ses = [] -sns = ["serde_with"] +ses = ["chrono"] +sns = ["chrono", "serde_with"] sqs = ["serde_with"] streams = [] diff --git a/lambda-events/src/custom_serde/codebuild_time.rs b/lambda-events/src/custom_serde/codebuild_time.rs index c57ccd6a..94d0e2f5 100644 --- a/lambda-events/src/custom_serde/codebuild_time.rs +++ b/lambda-events/src/custom_serde/codebuild_time.rs @@ -1,6 +1,9 @@ use chrono::{DateTime, TimeZone, Utc}; -use serde::de::{Deserialize, Deserializer, Error as DeError, Visitor}; use serde::ser::Serializer; +use serde::{ + de::{Deserializer, Error as DeError, Visitor}, + Deserialize, +}; use std::fmt; // Jan 2, 2006 3:04:05 PM @@ -10,7 +13,7 @@ struct TimeVisitor; impl<'de> Visitor<'de> for TimeVisitor { type Value = DateTime; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "valid codebuild time: {}", CODEBUILD_TIME_FORMAT) } @@ -74,7 +77,7 @@ mod tests { #[serde(with = "str_time")] pub date: TestTime, } - let data = json!({ + let data = serde_json::json!({ "date": "Sep 1, 2017 4:12:29 PM" }); @@ -92,7 +95,7 @@ mod tests { #[serde(with = "optional_time")] pub date: Option, } - let data = json!({ + let data = serde_json::json!({ "date": "Sep 1, 2017 4:12:29 PM" }); diff --git a/lambda-events/src/custom_serde/float_unix_epoch.rs b/lambda-events/src/custom_serde/float_unix_epoch.rs index 54fc64e4..82fd51df 100644 --- a/lambda-events/src/custom_serde/float_unix_epoch.rs +++ b/lambda-events/src/custom_serde/float_unix_epoch.rs @@ -14,13 +14,13 @@ fn ne_timestamp(ts: T) -> SerdeError { } impl fmt::Debug for SerdeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "ChronoSerdeError({})", self) } } impl fmt::Display for SerdeError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { SerdeError::NonExistent { ref timestamp } => { write!(f, "value is not a legal timestamp: {}", timestamp) @@ -77,7 +77,7 @@ where impl<'de> de::Visitor<'de> for SecondsFloatTimestampVisitor { type Value = DateTime; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a unix timestamp as a float") } diff --git a/lambda-events/src/custom_serde/headers.rs b/lambda-events/src/custom_serde/headers.rs index 904ccd9b..9cb89e40 100644 --- a/lambda-events/src/custom_serde/headers.rs +++ b/lambda-events/src/custom_serde/headers.rs @@ -49,7 +49,7 @@ impl<'de> Visitor<'de> for HeaderMapVisitor { type Value = HeaderMap; // Format a message stating what data this Visitor expects to receive. - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("lots of things can go wrong with HeaderMap") } @@ -81,7 +81,7 @@ impl<'de> Visitor<'de> for HeaderMapVisitor { let mut map = HeaderMap::with_capacity(access.size_hint().unwrap_or(0)); if !self.is_human_readable { - while let Some((key, arr)) = access.next_entry::, Vec>>()? { + while let Some((key, arr)) = access.next_entry::, Vec>>()? { let key = HeaderName::from_bytes(key.as_bytes()) .map_err(|_| de::Error::invalid_value(Unexpected::Str(&key), &self))?; for val in arr { @@ -91,7 +91,7 @@ impl<'de> Visitor<'de> for HeaderMapVisitor { } } } else { - while let Some((key, val)) = access.next_entry::, OneOrMore>()? { + while let Some((key, val)) = access.next_entry::, OneOrMore<'_>>()? { let key = HeaderName::from_bytes(key.as_bytes()) .map_err(|_| de::Error::invalid_value(Unexpected::Str(&key), &self))?; match val { @@ -135,6 +135,7 @@ where #[cfg(test)] mod tests { use super::*; + use serde::{Deserialize, Serialize}; #[test] fn test_deserialize_missing_http_headers() { @@ -143,7 +144,7 @@ mod tests { #[serde(deserialize_with = "deserialize_headers", default)] pub headers: HeaderMap, } - let data = json!({ + let data = serde_json::json!({ "not_headers": {} }); @@ -161,7 +162,7 @@ mod tests { #[serde(serialize_with = "serialize_multi_value_headers")] headers: HeaderMap, } - let data = json!({ + let data = serde_json::json!({ "headers": { "Accept": ["*/*"] } @@ -181,7 +182,7 @@ mod tests { #[serde(deserialize_with = "deserialize_headers")] headers: HeaderMap, } - let data = json!({ "headers": null }); + let data = serde_json::json!({ "headers": null }); let decoded: Test = serde_json::from_value(data).unwrap(); assert!(decoded.headers.is_empty()); diff --git a/lambda-events/src/custom_serde/http_method.rs b/lambda-events/src/custom_serde/http_method.rs index 6060a429..63a98eb4 100644 --- a/lambda-events/src/custom_serde/http_method.rs +++ b/lambda-events/src/custom_serde/http_method.rs @@ -11,7 +11,7 @@ struct MethodVisitor; impl<'de> Visitor<'de> for MethodVisitor { type Value = Method; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { write!(formatter, "valid method name") } @@ -56,6 +56,7 @@ pub fn serialize_optional(method: &Option, ser: S) -> Res #[cfg(test)] mod tests { use super::*; + use serde::{Deserialize, Serialize}; #[test] fn test_http_method_serializer() { @@ -64,7 +65,7 @@ mod tests { #[serde(with = "crate::custom_serde::http_method")] pub method: http::Method, } - let data = json!({ + let data = serde_json::json!({ "method": "DELETE" }); let decoded: Test = serde_json::from_value(data.clone()).unwrap(); @@ -83,7 +84,7 @@ mod tests { #[serde(default)] pub method: Option, } - let data = json!({ + let data = serde_json::json!({ "method": "DELETE" }); let decoded: Test = serde_json::from_value(data.clone()).unwrap(); @@ -92,11 +93,11 @@ mod tests { let recoded = serde_json::to_value(decoded).unwrap(); assert_eq!(data, recoded); - let data = json!({ "method": null }); + let data = serde_json::json!({ "method": null }); let decoded: Test = serde_json::from_value(data).unwrap(); assert_eq!(None, decoded.method); - let data = json!({}); + let data = serde_json::json!({}); let decoded: Test = serde_json::from_value(data).unwrap(); assert_eq!(None, decoded.method); } diff --git a/lambda-events/src/custom_serde/mod.rs b/lambda-events/src/custom_serde/mod.rs index e2c44af9..65f0f89a 100644 --- a/lambda-events/src/custom_serde/mod.rs +++ b/lambda-events/src/custom_serde/mod.rs @@ -1,7 +1,4 @@ -#[allow(unused)] use base64::Engine; -use chrono::{DateTime, Duration, TimeZone, Utc}; -use serde; use serde::de::{Deserialize, Deserializer, Error as DeError}; use serde::ser::Serializer; use std::collections::HashMap; @@ -34,89 +31,6 @@ pub(crate) mod float_unix_epoch; #[cfg(any(feature = "alb", feature = "apigw"))] pub(crate) mod http_method; -fn normalize_timestamp<'de, D>(deserializer: D) -> Result<(u64, u64), D::Error> -where - D: Deserializer<'de>, -{ - #[derive(Deserialize)] - #[serde(untagged)] - enum StringOrNumber { - String(String), - Float(f64), - Int(u64), - } - - let input: f64 = match StringOrNumber::deserialize(deserializer)? { - StringOrNumber::String(s) => s.parse::().map_err(DeError::custom)?, - StringOrNumber::Float(f) => f, - StringOrNumber::Int(i) => i as f64, - }; - - // We need to do this due to floating point issues. - let input_as_string = format!("{}", input); - let parts: Result, _> = input_as_string - .split('.') - .map(|x| x.parse::().map_err(DeError::custom)) - .collect(); - let parts = parts?; - if parts.len() > 1 { - Ok((parts[0], parts[1])) - } else { - Ok((parts[0], 0)) - } -} - -pub(crate) fn serialize_milliseconds(date: &DateTime, serializer: S) -> Result -where - S: Serializer, -{ - let ts_with_millis = date.timestamp_millis(); - serializer.serialize_str(&ts_with_millis.to_string()) -} - -pub(crate) fn deserialize_milliseconds<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let (whole, frac) = normalize_timestamp(deserializer)?; - assert_eq!(frac, 0); - let seconds: f64 = whole as f64 / 1000.0; - let milliseconds: u32 = (seconds.fract() * 1000f64) as u32; - let nanos = milliseconds * 1_000_000; - Utc.timestamp_opt(seconds as i64, nanos) - .latest() - .ok_or_else(|| D::Error::custom("invalid timestamp")) -} - -pub(crate) fn serialize_seconds(date: &DateTime, serializer: S) -> Result -where - S: Serializer, -{ - let seconds = date.timestamp(); - let milliseconds = date.timestamp_subsec_millis(); - let whole_seconds = seconds + (milliseconds as i64 / 1000); - let subsec_millis = milliseconds % 1000; - if milliseconds > 0 { - let combined = format!("{}.{:03}", whole_seconds, subsec_millis); - serializer.serialize_str(&combined) - } else { - serializer.serialize_str(&whole_seconds.to_string()) - } -} - -#[allow(dead_code)] -pub(crate) fn deserialize_seconds<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let (whole, frac) = normalize_timestamp(deserializer)?; - let seconds = whole; - let nanos = frac * 1_000_000; - Utc.timestamp_opt(seconds as i64, nanos as u32) - .latest() - .ok_or_else(|| D::Error::custom("invalid timestamp")) -} - pub(crate) fn deserialize_base64<'de, D>(deserializer: D) -> Result, D::Error> where D: Deserializer<'de>, @@ -159,46 +73,13 @@ where Ok(opt.unwrap_or_default()) } -pub(crate) fn serialize_duration_seconds(duration: &Duration, serializer: S) -> Result -where - S: Serializer, -{ - let seconds = duration.num_seconds(); - - serializer.serialize_i64(seconds) -} - -pub(crate) fn deserialize_duration_seconds<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let seconds = f64::deserialize(deserializer)?; - Ok(Duration::seconds(seconds as i64)) -} - -pub(crate) fn serialize_duration_minutes(duration: &Duration, serializer: S) -> Result -where - S: Serializer, -{ - let minutes = duration.num_minutes(); - - serializer.serialize_i64(minutes) -} - -pub(crate) fn deserialize_duration_minutes<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let minutes = f64::deserialize(deserializer)?; - Ok(Duration::minutes(minutes as i64)) -} - /// Deserializes `HashMap<_>`, mapping JSON `null` to an empty map. #[cfg(any( feature = "alb", feature = "apigw", feature = "cloudwatch_events", feature = "code_commit", + feature = "cognito", test ))] pub(crate) fn deserialize_nullish_boolean<'de, D>(deserializer: D) -> Result @@ -214,7 +95,7 @@ where #[allow(deprecated)] mod test { use super::*; - use chrono::TimeZone; + use serde::{Deserialize, Serialize}; use serde_json; #[test] @@ -224,7 +105,7 @@ mod test { #[serde(deserialize_with = "deserialize_base64")] v: Vec, } - let data = json!({ + let data = serde_json::json!({ "v": "SGVsbG8gV29ybGQ=", }); let decoded: Test = serde_json::from_value(data).unwrap(); @@ -245,76 +126,6 @@ mod test { assert_eq!(encoded, r#"{"v":"SGVsbG8gV29ybGQ="}"#.to_string()); } - #[test] - fn test_deserialize_milliseconds() { - #[derive(Deserialize)] - struct Test { - #[serde(deserialize_with = "deserialize_milliseconds")] - v: DateTime, - } - let expected = Utc.ymd(2017, 10, 5).and_hms_nano(15, 33, 44, 302_000_000); - - // Test parsing strings. - let data = json!({ - "v": "1507217624302", - }); - let decoded: Test = serde_json::from_value(data).unwrap(); - assert_eq!(expected, decoded.v,); - // Test parsing ints. - let decoded: Test = serde_json::from_slice(r#"{"v":1507217624302}"#.as_bytes()).unwrap(); - assert_eq!(expected, decoded.v,); - // Test parsing floats. - let data = json!({ - "v": 1507217624302.0, - }); - let decoded: Test = serde_json::from_value(data).unwrap(); - assert_eq!(expected, decoded.v,); - } - - #[test] - fn test_serialize_milliseconds() { - #[derive(Serialize)] - struct Test { - #[serde(serialize_with = "serialize_milliseconds")] - v: DateTime, - } - let instance = Test { - v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 99_888_777), - }; - let encoded = serde_json::to_string(&instance).unwrap(); - assert_eq!(encoded, String::from(r#"{"v":"427683600099"}"#)); - } - - #[test] - fn test_serialize_seconds() { - #[derive(Serialize)] - struct Test { - #[serde(serialize_with = "serialize_seconds")] - v: DateTime, - } - - // Make sure nanoseconds are chopped off. - let instance = Test { - v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 99), - }; - let encoded = serde_json::to_string(&instance).unwrap(); - assert_eq!(encoded, String::from(r#"{"v":"427683600"}"#)); - - // Make sure milliseconds are included. - let instance = Test { - v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 2_000_000), - }; - let encoded = serde_json::to_string(&instance).unwrap(); - assert_eq!(encoded, String::from(r#"{"v":"427683600.002"}"#)); - - // Make sure milliseconds are included. - let instance = Test { - v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 1_234_000_000), - }; - let encoded = serde_json::to_string(&instance).unwrap(); - assert_eq!(encoded, String::from(r#"{"v":"427683601.234"}"#)); - } - #[test] fn test_deserialize_map() { #[derive(Deserialize)] @@ -322,13 +133,13 @@ mod test { #[serde(deserialize_with = "deserialize_lambda_map")] v: HashMap, } - let input = json!({ + let input = serde_json::json!({ "v": {}, }); let decoded: Test = serde_json::from_value(input).unwrap(); assert_eq!(HashMap::new(), decoded.v); - let input = json!({ + let input = serde_json::json!({ "v": null, }); let decoded: Test = serde_json::from_value(input).unwrap(); @@ -343,93 +154,19 @@ mod test { #[serde(deserialize_with = "deserialize_lambda_dynamodb_item")] v: serde_dynamo::Item, } - let input = json!({ + let input = serde_json::json!({ "v": {}, }); let decoded: Test = serde_json::from_value(input).unwrap(); assert_eq!(serde_dynamo::Item::from(HashMap::new()), decoded.v); - let input = json!({ + let input = serde_json::json!({ "v": null, }); let decoded: Test = serde_json::from_value(input).unwrap(); assert_eq!(serde_dynamo::Item::from(HashMap::new()), decoded.v); } - #[test] - fn test_deserialize_duration_seconds() { - #[derive(Deserialize)] - struct Test { - #[serde(deserialize_with = "deserialize_duration_seconds")] - v: Duration, - } - - let expected = Duration::seconds(36); - - let data = json!({ - "v": 36, - }); - let decoded: Test = serde_json::from_value(data).unwrap(); - assert_eq!(expected, decoded.v,); - - let data = json!({ - "v": 36.1, - }); - let decoded: Test = serde_json::from_value(data).unwrap(); - assert_eq!(expected, decoded.v,); - } - - #[test] - fn test_serialize_duration_seconds() { - #[derive(Serialize)] - struct Test { - #[serde(serialize_with = "serialize_duration_seconds")] - v: Duration, - } - let instance = Test { - v: Duration::seconds(36), - }; - let encoded = serde_json::to_string(&instance).unwrap(); - assert_eq!(encoded, String::from(r#"{"v":36}"#)); - } - - #[test] - fn test_deserialize_duration_minutes() { - #[derive(Deserialize)] - struct Test { - #[serde(deserialize_with = "deserialize_duration_minutes")] - v: Duration, - } - - let expected = Duration::minutes(36); - - let data = json!({ - "v": 36, - }); - let decoded: Test = serde_json::from_value(data).unwrap(); - assert_eq!(expected, decoded.v,); - - let data = json!({ - "v": 36.1, - }); - let decoded: Test = serde_json::from_value(data).unwrap(); - assert_eq!(expected, decoded.v,); - } - - #[test] - fn test_serialize_duration_minutes() { - #[derive(Serialize)] - struct Test { - #[serde(serialize_with = "serialize_duration_minutes")] - v: Duration, - } - let instance = Test { - v: Duration::minutes(36), - }; - let encoded = serde_json::to_string(&instance).unwrap(); - assert_eq!(encoded, String::from(r#"{"v":36}"#)); - } - #[test] fn test_deserialize_nullish_boolean() { #[derive(Deserialize)] diff --git a/lambda-events/src/encodings.rs b/lambda-events/src/encodings/http.rs similarity index 75% rename from lambda-events/src/encodings.rs rename to lambda-events/src/encodings/http.rs index 42dd15a7..effb48f4 100644 --- a/lambda-events/src/encodings.rs +++ b/lambda-events/src/encodings/http.rs @@ -1,124 +1,9 @@ -use super::custom_serde::*; -use chrono::{DateTime, Duration, Utc}; -use std::{borrow::Cow, mem::take, ops::Deref, ops::DerefMut, pin::Pin, task::Poll}; - use base64::display::Base64Display; use bytes::Bytes; use http_body::{Body as HttpBody, SizeHint}; use serde::de::{Deserialize, Deserializer, Error as DeError, Visitor}; use serde::ser::{Error as SerError, Serialize, Serializer}; - -pub type Error = Box; - -/// Binary data encoded in base64. -#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] -pub struct Base64Data( - #[serde(deserialize_with = "deserialize_base64")] - #[serde(serialize_with = "serialize_base64")] - pub Vec, -); - -impl Deref for Base64Data { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Base64Data { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// Timestamp with millisecond precision. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct MillisecondTimestamp( - #[serde(deserialize_with = "deserialize_milliseconds")] - #[serde(serialize_with = "serialize_milliseconds")] - pub DateTime, -); - -impl Deref for MillisecondTimestamp { - type Target = DateTime; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for MillisecondTimestamp { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// Timestamp with second precision. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct SecondTimestamp( - #[serde(deserialize_with = "deserialize_seconds")] - #[serde(serialize_with = "serialize_seconds")] - pub DateTime, -); - -impl Deref for SecondTimestamp { - type Target = DateTime; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for SecondTimestamp { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// Duration with second precision. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct SecondDuration( - #[serde(deserialize_with = "deserialize_duration_seconds")] - #[serde(serialize_with = "serialize_duration_seconds")] - pub Duration, -); - -impl Deref for SecondDuration { - type Target = Duration; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for SecondDuration { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -/// Duration with minute precision. -#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] -pub struct MinuteDuration( - #[serde(deserialize_with = "deserialize_duration_minutes")] - #[serde(serialize_with = "serialize_duration_minutes")] - pub Duration, -); - -impl Deref for MinuteDuration { - type Target = Duration; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for MinuteDuration { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} +use std::{borrow::Cow, mem::take, ops::Deref, pin::Pin, task::Poll}; /// Representation of http request and response bodies as supported /// by API Gateway and ALBs. @@ -313,7 +198,7 @@ impl<'de> Deserialize<'de> for Body { impl<'de> Visitor<'de> for BodyVisitor { type Value = Body; - fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { formatter.write_str("string") } @@ -331,7 +216,7 @@ impl<'de> Deserialize<'de> for Body { impl HttpBody for Body { type Data = Bytes; - type Error = Error; + type Error = super::Error; fn poll_data( self: Pin<&mut Self>, diff --git a/lambda-events/src/encodings/mod.rs b/lambda-events/src/encodings/mod.rs new file mode 100644 index 00000000..ccc92684 --- /dev/null +++ b/lambda-events/src/encodings/mod.rs @@ -0,0 +1,37 @@ +use serde::{Deserialize, Serialize}; +use std::{ops::Deref, ops::DerefMut}; + +#[cfg(feature = "chrono")] +mod time; +use crate::custom_serde::{deserialize_base64, serialize_base64}; + +#[cfg(feature = "chrono")] +pub use self::time::*; +#[cfg(feature = "http")] +mod http; +#[cfg(feature = "http")] +pub use self::http::*; + +pub type Error = Box; + +/// Binary data encoded in base64. +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct Base64Data( + #[serde(deserialize_with = "deserialize_base64")] + #[serde(serialize_with = "serialize_base64")] + pub Vec, +); + +impl Deref for Base64Data { + type Target = Vec; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for Base64Data { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} diff --git a/lambda-events/src/encodings/time.rs b/lambda-events/src/encodings/time.rs new file mode 100644 index 00000000..390927ca --- /dev/null +++ b/lambda-events/src/encodings/time.rs @@ -0,0 +1,363 @@ +use chrono::{DateTime, Duration, TimeZone, Utc}; +use serde::ser::Serializer; +use serde::{ + de::{Deserializer, Error as DeError}, + Deserialize, Serialize, +}; +use std::ops::{Deref, DerefMut}; + +/// Timestamp with millisecond precision. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct MillisecondTimestamp( + #[serde(deserialize_with = "deserialize_milliseconds")] + #[serde(serialize_with = "serialize_milliseconds")] + pub DateTime, +); + +impl Deref for MillisecondTimestamp { + type Target = DateTime; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for MillisecondTimestamp { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// Timestamp with second precision. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct SecondTimestamp( + #[serde(deserialize_with = "deserialize_seconds")] + #[serde(serialize_with = "serialize_seconds")] + pub DateTime, +); + +impl Deref for SecondTimestamp { + type Target = DateTime; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SecondTimestamp { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// Duration with second precision. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct SecondDuration( + #[serde(deserialize_with = "deserialize_duration_seconds")] + #[serde(serialize_with = "serialize_duration_seconds")] + pub Duration, +); + +impl Deref for SecondDuration { + type Target = Duration; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for SecondDuration { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +/// Duration with minute precision. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct MinuteDuration( + #[serde(deserialize_with = "deserialize_duration_minutes")] + #[serde(serialize_with = "serialize_duration_minutes")] + pub Duration, +); + +impl Deref for MinuteDuration { + type Target = Duration; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DerefMut for MinuteDuration { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +fn serialize_milliseconds(date: &DateTime, serializer: S) -> Result +where + S: Serializer, +{ + let ts_with_millis = date.timestamp_millis(); + serializer.serialize_str(&ts_with_millis.to_string()) +} + +fn deserialize_milliseconds<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let (whole, frac) = normalize_timestamp(deserializer)?; + assert_eq!(frac, 0); + let seconds: f64 = whole as f64 / 1000.0; + let milliseconds: u32 = (seconds.fract() * 1000f64) as u32; + let nanos = milliseconds * 1_000_000; + Utc.timestamp_opt(seconds as i64, nanos) + .latest() + .ok_or_else(|| D::Error::custom("invalid timestamp")) +} + +fn serialize_seconds(date: &DateTime, serializer: S) -> Result +where + S: Serializer, +{ + let seconds = date.timestamp(); + let milliseconds = date.timestamp_subsec_millis(); + let whole_seconds = seconds + (milliseconds as i64 / 1000); + let subsec_millis = milliseconds % 1000; + if milliseconds > 0 { + let combined = format!("{}.{:03}", whole_seconds, subsec_millis); + serializer.serialize_str(&combined) + } else { + serializer.serialize_str(&whole_seconds.to_string()) + } +} + +fn deserialize_seconds<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let (whole, frac) = normalize_timestamp(deserializer)?; + let seconds = whole; + let nanos = frac * 1_000_000; + Utc.timestamp_opt(seconds as i64, nanos as u32) + .latest() + .ok_or_else(|| D::Error::custom("invalid timestamp")) +} + +fn serialize_duration_seconds(duration: &Duration, serializer: S) -> Result +where + S: Serializer, +{ + let seconds = duration.num_seconds(); + + serializer.serialize_i64(seconds) +} + +fn deserialize_duration_seconds<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let seconds = f64::deserialize(deserializer)?; + Ok(Duration::seconds(seconds as i64)) +} + +fn serialize_duration_minutes(duration: &Duration, serializer: S) -> Result +where + S: Serializer, +{ + let minutes = duration.num_minutes(); + + serializer.serialize_i64(minutes) +} + +fn deserialize_duration_minutes<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + let minutes = f64::deserialize(deserializer)?; + Ok(Duration::minutes(minutes as i64)) +} + +fn normalize_timestamp<'de, D>(deserializer: D) -> Result<(u64, u64), D::Error> +where + D: Deserializer<'de>, +{ + #[derive(Deserialize)] + #[serde(untagged)] + enum StringOrNumber { + String(String), + Float(f64), + Int(u64), + } + + let input: f64 = match StringOrNumber::deserialize(deserializer)? { + StringOrNumber::String(s) => s.parse::().map_err(DeError::custom)?, + StringOrNumber::Float(f) => f, + StringOrNumber::Int(i) => i as f64, + }; + + // We need to do this due to floating point issues. + let input_as_string = format!("{}", input); + let parts: Result, _> = input_as_string + .split('.') + .map(|x| x.parse::().map_err(DeError::custom)) + .collect(); + let parts = parts?; + if parts.len() > 1 { + Ok((parts[0], parts[1])) + } else { + Ok((parts[0], 0)) + } +} + +#[cfg(test)] +#[allow(deprecated)] +mod test { + use super::*; + use chrono::TimeZone; + use serde_json; + + #[test] + fn test_deserialize_milliseconds() { + #[derive(Deserialize)] + struct Test { + #[serde(deserialize_with = "deserialize_milliseconds")] + v: DateTime, + } + let expected = Utc.ymd(2017, 10, 5).and_hms_nano(15, 33, 44, 302_000_000); + + // Test parsing strings. + let data = serde_json::json!({ + "v": "1507217624302", + }); + let decoded: Test = serde_json::from_value(data).unwrap(); + assert_eq!(expected, decoded.v,); + // Test parsing ints. + let decoded: Test = serde_json::from_slice(r#"{"v":1507217624302}"#.as_bytes()).unwrap(); + assert_eq!(expected, decoded.v,); + // Test parsing floats. + let data = serde_json::json!({ + "v": 1507217624302.0, + }); + let decoded: Test = serde_json::from_value(data).unwrap(); + assert_eq!(expected, decoded.v,); + } + + #[test] + fn test_serialize_milliseconds() { + #[derive(Serialize)] + struct Test { + #[serde(serialize_with = "serialize_milliseconds")] + v: DateTime, + } + let instance = Test { + v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 99_888_777), + }; + let encoded = serde_json::to_string(&instance).unwrap(); + assert_eq!(encoded, String::from(r#"{"v":"427683600099"}"#)); + } + + #[test] + fn test_serialize_seconds() { + #[derive(Serialize)] + struct Test { + #[serde(serialize_with = "serialize_seconds")] + v: DateTime, + } + + // Make sure nanoseconds are chopped off. + let instance = Test { + v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 99), + }; + let encoded = serde_json::to_string(&instance).unwrap(); + assert_eq!(encoded, String::from(r#"{"v":"427683600"}"#)); + + // Make sure milliseconds are included. + let instance = Test { + v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 2_000_000), + }; + let encoded = serde_json::to_string(&instance).unwrap(); + assert_eq!(encoded, String::from(r#"{"v":"427683600.002"}"#)); + + // Make sure milliseconds are included. + let instance = Test { + v: Utc.ymd(1983, 7, 22).and_hms_nano(1, 0, 0, 1_234_000_000), + }; + let encoded = serde_json::to_string(&instance).unwrap(); + assert_eq!(encoded, String::from(r#"{"v":"427683601.234"}"#)); + } + + #[test] + fn test_deserialize_duration_seconds() { + #[derive(Deserialize)] + struct Test { + #[serde(deserialize_with = "deserialize_duration_seconds")] + v: Duration, + } + + let expected = Duration::seconds(36); + + let data = serde_json::json!({ + "v": 36, + }); + let decoded: Test = serde_json::from_value(data).unwrap(); + assert_eq!(expected, decoded.v,); + + let data = serde_json::json!({ + "v": 36.1, + }); + let decoded: Test = serde_json::from_value(data).unwrap(); + assert_eq!(expected, decoded.v,); + } + + #[test] + fn test_serialize_duration_seconds() { + #[derive(Serialize)] + struct Test { + #[serde(serialize_with = "serialize_duration_seconds")] + v: Duration, + } + let instance = Test { + v: Duration::seconds(36), + }; + let encoded = serde_json::to_string(&instance).unwrap(); + assert_eq!(encoded, String::from(r#"{"v":36}"#)); + } + + #[test] + fn test_deserialize_duration_minutes() { + #[derive(Deserialize)] + struct Test { + #[serde(deserialize_with = "deserialize_duration_minutes")] + v: Duration, + } + + let expected = Duration::minutes(36); + + let data = serde_json::json!({ + "v": 36, + }); + let decoded: Test = serde_json::from_value(data).unwrap(); + assert_eq!(expected, decoded.v,); + + let data = serde_json::json!({ + "v": 36.1, + }); + let decoded: Test = serde_json::from_value(data).unwrap(); + assert_eq!(expected, decoded.v,); + } + + #[test] + fn test_serialize_duration_minutes() { + #[derive(Serialize)] + struct Test { + #[serde(serialize_with = "serialize_duration_minutes")] + v: Duration, + } + let instance = Test { + v: Duration::minutes(36), + }; + let encoded = serde_json::to_string(&instance).unwrap(); + assert_eq!(encoded, String::from(r#"{"v":36}"#)); + } +} diff --git a/lambda-events/src/event/activemq/mod.rs b/lambda-events/src/event/activemq/mod.rs index fcb490ec..9469ece4 100644 --- a/lambda-events/src/event/activemq/mod.rs +++ b/lambda-events/src/event/activemq/mod.rs @@ -1,6 +1,8 @@ -use crate::custom_serde::*; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ActiveMqEvent { @@ -52,7 +54,7 @@ pub struct ActiveMqDestination { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "activemq")] diff --git a/lambda-events/src/event/alb/mod.rs b/lambda-events/src/event/alb/mod.rs index b9a69ce5..259dce23 100644 --- a/lambda-events/src/event/alb/mod.rs +++ b/lambda-events/src/event/alb/mod.rs @@ -1,7 +1,10 @@ -use crate::custom_serde::{http_method, serialize_headers, serialize_multi_value_headers}; +use crate::custom_serde::{ + deserialize_headers, deserialize_nullish_boolean, http_method, serialize_headers, serialize_multi_value_headers, +}; use crate::encodings::Body; use http::{HeaderMap, Method}; use query_map::QueryMap; +use serde::{Deserialize, Serialize}; /// `AlbTargetGroupRequest` contains data originating from the ALB Lambda target group integration #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] @@ -15,13 +18,14 @@ pub struct AlbTargetGroupRequest { pub query_string_parameters: QueryMap, #[serde(default)] pub multi_value_query_string_parameters: QueryMap, - #[serde(deserialize_with = "http_serde::header_map::deserialize", default)] + #[serde(deserialize_with = "deserialize_headers", default)] #[serde(serialize_with = "serialize_headers")] pub headers: HeaderMap, - #[serde(deserialize_with = "http_serde::header_map::deserialize", default)] + #[serde(deserialize_with = "deserialize_headers", default)] #[serde(serialize_with = "serialize_multi_value_headers")] pub multi_value_headers: HeaderMap, pub request_context: AlbTargetGroupRequestContext, + #[serde(default, deserialize_with = "deserialize_nullish_boolean")] pub is_base64_encoded: bool, pub body: Option, } @@ -57,6 +61,7 @@ pub struct AlbTargetGroupResponse { pub multi_value_headers: HeaderMap, #[serde(skip_serializing_if = "Option::is_none")] pub body: Option, + #[serde(default, deserialize_with = "deserialize_nullish_boolean")] pub is_base64_encoded: bool, } @@ -64,7 +69,7 @@ pub struct AlbTargetGroupResponse { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "alb")] diff --git a/lambda-events/src/event/apigw/mod.rs b/lambda-events/src/event/apigw/mod.rs index 196bff86..917f06aa 100644 --- a/lambda-events/src/event/apigw/mod.rs +++ b/lambda-events/src/event/apigw/mod.rs @@ -6,7 +6,7 @@ use crate::encodings::Body; use http::{HeaderMap, Method}; use query_map::QueryMap; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; @@ -751,7 +751,7 @@ pub struct IamPolicyStatement { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "apigw")] diff --git a/lambda-events/src/event/appsync/mod.rs b/lambda-events/src/event/appsync/mod.rs index 0ef67b7b..120fc9e3 100644 --- a/lambda-events/src/event/appsync/mod.rs +++ b/lambda-events/src/event/appsync/mod.rs @@ -1,9 +1,10 @@ -use crate::custom_serde::*; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + /// Deprecated: `AppSyncResolverTemplate` does not represent resolver events sent by AppSync. Instead directly model your input schema, or use map[string]string, json.RawMessage, interface{}, etc.. #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -121,7 +122,7 @@ where mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "appsync")] diff --git a/lambda-events/src/event/autoscaling/mod.rs b/lambda-events/src/event/autoscaling/mod.rs index ce0128c2..cc003daf 100644 --- a/lambda-events/src/event/autoscaling/mod.rs +++ b/lambda-events/src/event/autoscaling/mod.rs @@ -1,10 +1,11 @@ -use crate::custom_serde::*; use chrono::{DateTime, Utc}; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + /// `AutoScalingEvent` struct is used to parse the json for auto scaling event types // #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -47,7 +48,7 @@ where mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "autoscaling")] diff --git a/lambda-events/src/event/chime_bot/mod.rs b/lambda-events/src/event/chime_bot/mod.rs index ef57c6f9..6581ed2c 100644 --- a/lambda-events/src/event/chime_bot/mod.rs +++ b/lambda-events/src/event/chime_bot/mod.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/clientvpn/mod.rs b/lambda-events/src/event/clientvpn/mod.rs index f0e61dda..0e188704 100644 --- a/lambda-events/src/event/clientvpn/mod.rs +++ b/lambda-events/src/event/clientvpn/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct ClientVpnConnectionHandlerRequest { @@ -47,7 +49,7 @@ pub struct ClientVpnConnectionHandlerResponse { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "clientvpn")] diff --git a/lambda-events/src/event/cloudwatch_events/cloudtrail.rs b/lambda-events/src/event/cloudwatch_events/cloudtrail.rs index aefa7f4a..36d071ea 100644 --- a/lambda-events/src/event/cloudwatch_events/cloudtrail.rs +++ b/lambda-events/src/event/cloudwatch_events/cloudtrail.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] diff --git a/lambda-events/src/event/cloudwatch_events/codedeploy.rs b/lambda-events/src/event/cloudwatch_events/codedeploy.rs index 0dd2b540..1bd44297 100644 --- a/lambda-events/src/event/cloudwatch_events/codedeploy.rs +++ b/lambda-events/src/event/cloudwatch_events/codedeploy.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/codepipeline.rs b/lambda-events/src/event/cloudwatch_events/codepipeline.rs index 86a1de15..ce5fa47c 100644 --- a/lambda-events/src/event/cloudwatch_events/codepipeline.rs +++ b/lambda-events/src/event/cloudwatch_events/codepipeline.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/ec2.rs b/lambda-events/src/event/cloudwatch_events/ec2.rs index c4e26b4e..c8eb7834 100644 --- a/lambda-events/src/event/cloudwatch_events/ec2.rs +++ b/lambda-events/src/event/cloudwatch_events/ec2.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/emr.rs b/lambda-events/src/event/cloudwatch_events/emr.rs index 942e5984..87fb8085 100644 --- a/lambda-events/src/event/cloudwatch_events/emr.rs +++ b/lambda-events/src/event/cloudwatch_events/emr.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/gamelift.rs b/lambda-events/src/event/cloudwatch_events/gamelift.rs index 1369a793..fb5c50a7 100644 --- a/lambda-events/src/event/cloudwatch_events/gamelift.rs +++ b/lambda-events/src/event/cloudwatch_events/gamelift.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; use crate::custom_serde::deserialize_nullish_boolean; diff --git a/lambda-events/src/event/cloudwatch_events/glue.rs b/lambda-events/src/event/cloudwatch_events/glue.rs index f752f53e..08f05929 100644 --- a/lambda-events/src/event/cloudwatch_events/glue.rs +++ b/lambda-events/src/event/cloudwatch_events/glue.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/health.rs b/lambda-events/src/event/cloudwatch_events/health.rs index 3c8acbf9..2a6a82e3 100644 --- a/lambda-events/src/event/cloudwatch_events/health.rs +++ b/lambda-events/src/event/cloudwatch_events/health.rs @@ -1,8 +1,6 @@ +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use serde_derive::Deserialize; -use serde_derive::Serialize; - #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Event { diff --git a/lambda-events/src/event/cloudwatch_events/kms.rs b/lambda-events/src/event/cloudwatch_events/kms.rs index ac6f8926..74a76e70 100644 --- a/lambda-events/src/event/cloudwatch_events/kms.rs +++ b/lambda-events/src/event/cloudwatch_events/kms.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/macie.rs b/lambda-events/src/event/cloudwatch_events/macie.rs index 4ce78b71..37d18d7a 100644 --- a/lambda-events/src/event/cloudwatch_events/macie.rs +++ b/lambda-events/src/event/cloudwatch_events/macie.rs @@ -1,8 +1,6 @@ +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use serde_derive::Deserialize; -use serde_derive::Serialize; - #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct Alert { diff --git a/lambda-events/src/event/cloudwatch_events/mod.rs b/lambda-events/src/event/cloudwatch_events/mod.rs index 3c39e3d3..425de865 100644 --- a/lambda-events/src/event/cloudwatch_events/mod.rs +++ b/lambda-events/src/event/cloudwatch_events/mod.rs @@ -1,6 +1,6 @@ use chrono::{DateTime, Utc}; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; pub mod cloudtrail; diff --git a/lambda-events/src/event/cloudwatch_events/opsworks.rs b/lambda-events/src/event/cloudwatch_events/opsworks.rs index c75f1b5e..d1c192e5 100644 --- a/lambda-events/src/event/cloudwatch_events/opsworks.rs +++ b/lambda-events/src/event/cloudwatch_events/opsworks.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/signin.rs b/lambda-events/src/event/cloudwatch_events/signin.rs index 4d256e3b..1cd73e6e 100644 --- a/lambda-events/src/event/cloudwatch_events/signin.rs +++ b/lambda-events/src/event/cloudwatch_events/signin.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] diff --git a/lambda-events/src/event/cloudwatch_events/sms.rs b/lambda-events/src/event/cloudwatch_events/sms.rs index 33092b76..7d161822 100644 --- a/lambda-events/src/event/cloudwatch_events/sms.rs +++ b/lambda-events/src/event/cloudwatch_events/sms.rs @@ -1,5 +1,4 @@ -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/ssm.rs b/lambda-events/src/event/cloudwatch_events/ssm.rs index a826ed07..fa6ffc3b 100644 --- a/lambda-events/src/event/cloudwatch_events/ssm.rs +++ b/lambda-events/src/event/cloudwatch_events/ssm.rs @@ -1,8 +1,6 @@ +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use serde_derive::Deserialize; -use serde_derive::Serialize; - #[derive(Clone, Debug, Default, Deserialize, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct EC2AutomationStepStatusChange { diff --git a/lambda-events/src/event/cloudwatch_events/tag.rs b/lambda-events/src/event/cloudwatch_events/tag.rs index 573a99ea..d5bc9681 100644 --- a/lambda-events/src/event/cloudwatch_events/tag.rs +++ b/lambda-events/src/event/cloudwatch_events/tag.rs @@ -1,7 +1,6 @@ use std::collections::HashMap; -use serde_derive::Deserialize; -use serde_derive::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/cloudwatch_events/trustedadvisor.rs b/lambda-events/src/event/cloudwatch_events/trustedadvisor.rs index ce6cf79f..6a7e25d3 100644 --- a/lambda-events/src/event/cloudwatch_events/trustedadvisor.rs +++ b/lambda-events/src/event/cloudwatch_events/trustedadvisor.rs @@ -1,8 +1,6 @@ +use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use serde_derive::Deserialize; -use serde_derive::Serialize; - #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] pub struct CheckItemRefreshNotification { diff --git a/lambda-events/src/event/cloudwatch_logs/mod.rs b/lambda-events/src/event/cloudwatch_logs/mod.rs index 053974ec..0c9ad4a8 100644 --- a/lambda-events/src/event/cloudwatch_logs/mod.rs +++ b/lambda-events/src/event/cloudwatch_logs/mod.rs @@ -59,7 +59,7 @@ impl<'de> Deserialize<'de> for AwsLogs { impl<'de> Visitor<'de> for AwsLogsVisitor { type Value = AwsLogs; - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { formatter.write_str("a base64 gzipped string") } diff --git a/lambda-events/src/event/code_commit/mod.rs b/lambda-events/src/event/code_commit/mod.rs index 8b2e617f..87687cfd 100644 --- a/lambda-events/src/event/code_commit/mod.rs +++ b/lambda-events/src/event/code_commit/mod.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; use crate::custom_serde::deserialize_nullish_boolean; @@ -68,7 +69,7 @@ pub struct CodeCommitReference { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "code_commit")] diff --git a/lambda-events/src/event/codebuild/mod.rs b/lambda-events/src/event/codebuild/mod.rs index 2c6ddf39..a3839f92 100644 --- a/lambda-events/src/event/codebuild/mod.rs +++ b/lambda-events/src/event/codebuild/mod.rs @@ -1,8 +1,8 @@ -use crate::custom_serde::*; +use crate::custom_serde::{codebuild_time, CodeBuildNumber}; use crate::encodings::{MinuteDuration, SecondDuration}; use chrono::{DateTime, Utc}; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; pub type CodeBuildPhaseStatus = String; @@ -213,7 +213,7 @@ pub type CodeBuildTime = DateTime; mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "codebuild")] diff --git a/lambda-events/src/event/codedeploy/mod.rs b/lambda-events/src/event/codedeploy/mod.rs index 61bfc665..2ab37a82 100644 --- a/lambda-events/src/event/codedeploy/mod.rs +++ b/lambda-events/src/event/codedeploy/mod.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; pub type CodeDeployDeploymentState = String; @@ -68,7 +69,7 @@ pub struct CodeDeployEventDetail { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "codedeploy")] diff --git a/lambda-events/src/event/codepipeline_cloudwatch/mod.rs b/lambda-events/src/event/codepipeline_cloudwatch/mod.rs index d4d3477b..f26aa54f 100644 --- a/lambda-events/src/event/codepipeline_cloudwatch/mod.rs +++ b/lambda-events/src/event/codepipeline_cloudwatch/mod.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; pub type CodePipelineStageState = String; @@ -80,7 +81,7 @@ pub struct CodePipelineEventDetailType { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "codepipeline_cloudwatch")] diff --git a/lambda-events/src/event/codepipeline_job/mod.rs b/lambda-events/src/event/codepipeline_job/mod.rs index 0767b272..6c5d75f6 100644 --- a/lambda-events/src/event/codepipeline_job/mod.rs +++ b/lambda-events/src/event/codepipeline_job/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + /// `CodePipelineJobEvent` contains data from an event sent from AWS CodePipeline #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -115,7 +117,7 @@ pub struct CodePipelineArtifactCredentials { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "codepipeline_job")] diff --git a/lambda-events/src/event/cognito/mod.rs b/lambda-events/src/event/cognito/mod.rs index 99bc682b..6874ee24 100644 --- a/lambda-events/src/event/cognito/mod.rs +++ b/lambda-events/src/event/cognito/mod.rs @@ -1,9 +1,10 @@ -use crate::custom_serde::*; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; +use crate::custom_serde::{deserialize_lambda_map, deserialize_nullish_boolean}; + /// `CognitoEvent` contains data from an event sent from AWS Cognito Sync #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] @@ -457,7 +458,7 @@ pub struct CognitoEventUserPoolsCustomMessageResponse { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "cognito")] diff --git a/lambda-events/src/event/config/mod.rs b/lambda-events/src/event/config/mod.rs index bb5d0c11..0b03ecc5 100644 --- a/lambda-events/src/event/config/mod.rs +++ b/lambda-events/src/event/config/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + /// `ConfigEvent` contains data from an event sent from AWS Config #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -38,7 +40,7 @@ pub struct ConfigEvent { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "config")] diff --git a/lambda-events/src/event/connect/mod.rs b/lambda-events/src/event/connect/mod.rs index 62e86b52..bc640930 100644 --- a/lambda-events/src/event/connect/mod.rs +++ b/lambda-events/src/event/connect/mod.rs @@ -1,6 +1,8 @@ -use crate::custom_serde::*; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + /// `ConnectEvent` contains the data structure for a Connect event. #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] @@ -92,7 +94,7 @@ pub type ConnectResponse = HashMap; mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "connect")] diff --git a/lambda-events/src/event/dynamodb/attributes.rs b/lambda-events/src/event/dynamodb/attributes.rs index d2f32caf..aad2cd4b 100644 --- a/lambda-events/src/event/dynamodb/attributes.rs +++ b/lambda-events/src/event/dynamodb/attributes.rs @@ -1,5 +1,5 @@ use base64::Engine; -use event::serde_dynamo::AttributeValue; +use serde_dynamo::AttributeValue; use std::collections::HashMap; #[cfg(test)] diff --git a/lambda-events/src/event/dynamodb/mod.rs b/lambda-events/src/event/dynamodb/mod.rs index 00ff08e4..398f2dd5 100644 --- a/lambda-events/src/event/dynamodb/mod.rs +++ b/lambda-events/src/event/dynamodb/mod.rs @@ -1,6 +1,6 @@ -use crate::custom_serde::*; -use crate::streams::DynamoDbBatchItemFailure; +use crate::custom_serde::deserialize_lambda_dynamodb_item; use crate::time_window::*; +use crate::{custom_serde::float_unix_epoch, streams::DynamoDbBatchItemFailure}; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use std::fmt; @@ -252,7 +252,7 @@ mod test { use super::*; use chrono::TimeZone; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "dynamodb")] diff --git a/lambda-events/src/event/ecr_scan/mod.rs b/lambda-events/src/event/ecr_scan/mod.rs index 87dede6f..1ed91896 100644 --- a/lambda-events/src/event/ecr_scan/mod.rs +++ b/lambda-events/src/event/ecr_scan/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct EcrScanEvent { @@ -59,7 +61,7 @@ pub struct EcrScanEventFindingSeverityCounts { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "ecr_scan")] diff --git a/lambda-events/src/event/firehose/mod.rs b/lambda-events/src/event/firehose/mod.rs index 63ef3e1f..352342ec 100644 --- a/lambda-events/src/event/firehose/mod.rs +++ b/lambda-events/src/event/firehose/mod.rs @@ -1,5 +1,8 @@ -use crate::custom_serde::*; -use crate::encodings::{Base64Data, MillisecondTimestamp}; +use crate::{ + custom_serde::deserialize_lambda_map, + encodings::{Base64Data, MillisecondTimestamp}, +}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; /// `KinesisFirehoseEvent` represents the input event from Amazon Kinesis Firehose. It is used as the input parameter. @@ -73,7 +76,7 @@ pub struct KinesisFirehoseRecordMetadata { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "firehose")] diff --git a/lambda-events/src/event/iam/mod.rs b/lambda-events/src/event/iam/mod.rs index 1b73e44b..12bf7ba9 100644 --- a/lambda-events/src/event/iam/mod.rs +++ b/lambda-events/src/event/iam/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + /// `IamPolicyDocument` represents an IAM policy document. #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/iot/mod.rs b/lambda-events/src/event/iot/mod.rs index 9f45899f..31220b17 100644 --- a/lambda-events/src/event/iot/mod.rs +++ b/lambda-events/src/event/iot/mod.rs @@ -1,7 +1,8 @@ -use crate::custom_serde::*; +use crate::custom_serde::serialize_headers; use crate::encodings::Base64Data; use crate::iam::IamPolicyDocument; use http::HeaderMap; +use serde::{Deserialize, Serialize}; /// `IoTCoreCustomAuthorizerRequest` represents the request to an IoT Core custom authorizer. /// See https://docs.aws.amazon.com/iot/latest/developerguide/config-custom-auth.html @@ -75,7 +76,7 @@ pub struct IoTCoreCustomAuthorizerResponse { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "iot")] diff --git a/lambda-events/src/event/iot_1_click/mod.rs b/lambda-events/src/event/iot_1_click/mod.rs index 0e1c11b6..4ec47d71 100644 --- a/lambda-events/src/event/iot_1_click/mod.rs +++ b/lambda-events/src/event/iot_1_click/mod.rs @@ -1,6 +1,8 @@ -use crate::custom_serde::*; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + /// `IoTOneClickEvent` represents a click event published by clicking button type /// device. #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] @@ -57,8 +59,7 @@ pub struct IoTOneClickPlacementInfo { #[cfg(test)] mod test { use super::*; - - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "iot_1_click")] diff --git a/lambda-events/src/event/iot_button/mod.rs b/lambda-events/src/event/iot_button/mod.rs index 32ba8d5a..ac79e34b 100644 --- a/lambda-events/src/event/iot_button/mod.rs +++ b/lambda-events/src/event/iot_button/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct IoTButtonEvent { @@ -13,7 +15,7 @@ pub struct IoTButtonEvent { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "iot_button")] diff --git a/lambda-events/src/event/iot_deprecated/mod.rs b/lambda-events/src/event/iot_deprecated/mod.rs index 4304d7cd..12c1df99 100644 --- a/lambda-events/src/event/iot_deprecated/mod.rs +++ b/lambda-events/src/event/iot_deprecated/mod.rs @@ -1,4 +1,5 @@ use crate::iot::*; +use serde::{Deserialize, Serialize}; /// `IoTCustomAuthorizerRequest` contains data coming in to a custom IoT device gateway authorizer function. /// Deprecated: Use IoTCoreCustomAuthorizerRequest instead. `IoTCustomAuthorizerRequest` does not correctly model the request schema diff --git a/lambda-events/src/event/kafka/mod.rs b/lambda-events/src/event/kafka/mod.rs index 6c4d78fa..07299859 100644 --- a/lambda-events/src/event/kafka/mod.rs +++ b/lambda-events/src/event/kafka/mod.rs @@ -1,5 +1,5 @@ -use crate::custom_serde::*; -use crate::encodings::MillisecondTimestamp; +use crate::{custom_serde::deserialize_lambda_map, encodings::MillisecondTimestamp}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] @@ -35,7 +35,7 @@ pub struct KafkaRecord { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "kafka")] diff --git a/lambda-events/src/event/kinesis/analytics.rs b/lambda-events/src/event/kinesis/analytics.rs index 1704009e..74c95606 100644 --- a/lambda-events/src/event/kinesis/analytics.rs +++ b/lambda-events/src/event/kinesis/analytics.rs @@ -1,4 +1,5 @@ use crate::encodings::Base64Data; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/kinesis/event.rs b/lambda-events/src/event/kinesis/event.rs index c401fa72..0c43ae10 100644 --- a/lambda-events/src/event/kinesis/event.rs +++ b/lambda-events/src/event/kinesis/event.rs @@ -1,5 +1,6 @@ use crate::encodings::{Base64Data, SecondTimestamp}; use crate::time_window::{TimeWindowEventResponseProperties, TimeWindowProperties}; +use serde::{Deserialize, Serialize}; #[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] @@ -74,7 +75,7 @@ pub struct KinesisRecord { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "kinesis")] diff --git a/lambda-events/src/event/lambda_function_urls/mod.rs b/lambda-events/src/event/lambda_function_urls/mod.rs index d1567b56..37ddfe39 100644 --- a/lambda-events/src/event/lambda_function_urls/mod.rs +++ b/lambda-events/src/event/lambda_function_urls/mod.rs @@ -1,7 +1,9 @@ -use crate::custom_serde::*; use http::HeaderMap; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::{deserialize_lambda_map, serialize_headers}; + /// `LambdaFunctionUrlRequest` contains data coming from the HTTP request to a Lambda Function URL. #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/lex/mod.rs b/lambda-events/src/event/lex/mod.rs index a3593dfd..a058a249 100644 --- a/lambda-events/src/event/lex/mod.rs +++ b/lambda-events/src/event/lex/mod.rs @@ -1,6 +1,8 @@ -use crate::custom_serde::*; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + #[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct LexEvent { @@ -106,7 +108,7 @@ pub struct Attachment { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "lex")] diff --git a/lambda-events/src/event/mod.rs b/lambda-events/src/event/mod.rs index e7b8c7f7..1aa56697 100644 --- a/lambda-events/src/event/mod.rs +++ b/lambda-events/src/event/mod.rs @@ -67,8 +67,6 @@ pub mod connect; /// AWS Lambda event definitions for dynamodb. #[cfg(feature = "dynamodb")] -extern crate serde_dynamo; -#[cfg(feature = "dynamodb")] pub mod dynamodb; /// AWS Lambda event definitions for ecr_scan. diff --git a/lambda-events/src/event/rabbitmq/mod.rs b/lambda-events/src/event/rabbitmq/mod.rs index c8af802f..14a379a5 100644 --- a/lambda-events/src/event/rabbitmq/mod.rs +++ b/lambda-events/src/event/rabbitmq/mod.rs @@ -1,9 +1,10 @@ -use crate::custom_serde::*; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct RabbitMqEvent { @@ -62,7 +63,7 @@ where mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "rabbitmq")] diff --git a/lambda-events/src/event/s3/batch_job.rs b/lambda-events/src/event/s3/batch_job.rs index 8db71896..e3eb691e 100644 --- a/lambda-events/src/event/s3/batch_job.rs +++ b/lambda-events/src/event/s3/batch_job.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + /// `S3BatchJobEvent` encapsulates the detail of a s3 batch job #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/event/s3/event.rs b/lambda-events/src/event/s3/event.rs index b25cfdd2..13d514ad 100644 --- a/lambda-events/src/event/s3/event.rs +++ b/lambda-events/src/event/s3/event.rs @@ -1,7 +1,9 @@ -use crate::custom_serde::*; use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + /// `S3Event` which wrap an array of `S3Event`Record #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] #[serde(rename_all = "camelCase")] @@ -90,7 +92,7 @@ pub struct S3Object { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "s3")] diff --git a/lambda-events/src/event/s3/object_lambda.rs b/lambda-events/src/event/s3/object_lambda.rs index e31a751e..1eec2c0d 100644 --- a/lambda-events/src/event/s3/object_lambda.rs +++ b/lambda-events/src/event/s3/object_lambda.rs @@ -1,10 +1,11 @@ -use crate::custom_serde::*; use http::HeaderMap; use serde::de::DeserializeOwned; -use serde::ser::Serialize; +use serde::{Deserialize, Serialize}; use serde_json::Value; use std::collections::HashMap; +use crate::custom_serde::{deserialize_headers, serialize_headers}; + /// `S3ObjectLambdaEvent` contains data coming from S3 object lambdas /// See: https://docs.aws.amazon.com/AmazonS3/latest/userguide/olap-writing-lambda.html #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] @@ -117,7 +118,7 @@ pub struct SessionIssuer { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "s3")] diff --git a/lambda-events/src/event/ses/mod.rs b/lambda-events/src/event/ses/mod.rs index 3570652f..a4a97039 100644 --- a/lambda-events/src/event/ses/mod.rs +++ b/lambda-events/src/event/ses/mod.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; /// `SimpleEmailEvent` is the outer structure of an event sent via SES. #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] @@ -121,7 +122,7 @@ pub struct SimpleEmailDisposition { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "ses")] diff --git a/lambda-events/src/event/sns/mod.rs b/lambda-events/src/event/sns/mod.rs index 78193fcf..3c859d3e 100644 --- a/lambda-events/src/event/sns/mod.rs +++ b/lambda-events/src/event/sns/mod.rs @@ -1,9 +1,10 @@ -use crate::custom_serde::*; use chrono::{DateTime, Utc}; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::custom_serde::deserialize_lambda_map; + /// The `Event` notification event handled by Lambda /// /// [https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html](https://docs.aws.amazon.com/lambda/latest/dg/with-sns.html) @@ -178,7 +179,7 @@ pub struct MessageAttribute { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "sns")] diff --git a/lambda-events/src/event/sqs/mod.rs b/lambda-events/src/event/sqs/mod.rs index 5dc178b2..af4d3f21 100644 --- a/lambda-events/src/event/sqs/mod.rs +++ b/lambda-events/src/event/sqs/mod.rs @@ -1,4 +1,5 @@ -use crate::{custom_serde::*, encodings::Base64Data}; +use crate::custom_serde::deserialize_lambda_map; +use crate::encodings::Base64Data; use serde::de::DeserializeOwned; use serde::{Deserialize, Serialize}; use std::collections::HashMap; @@ -115,7 +116,7 @@ pub struct BatchItemFailure { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] #[cfg(feature = "sqs")] diff --git a/lambda-events/src/event/streams/mod.rs b/lambda-events/src/event/streams/mod.rs index 51a77121..9e0fd76f 100644 --- a/lambda-events/src/event/streams/mod.rs +++ b/lambda-events/src/event/streams/mod.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + /// `KinesisEventResponse` is the outer structure to report batch item failures for KinesisEvent. #[derive(Debug, Clone, Eq, PartialEq, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] diff --git a/lambda-events/src/lib.rs b/lambda-events/src/lib.rs index fa6cce05..564debd7 100644 --- a/lambda-events/src/lib.rs +++ b/lambda-events/src/lib.rs @@ -1,27 +1,13 @@ -extern crate base64; -extern crate http_serde; -#[cfg(test)] -#[macro_use] -extern crate pretty_assertions; -#[macro_use] -extern crate serde_derive; -#[cfg(test)] -#[macro_use] -extern crate serde_json; - -// Crates with types that we use publicly. Reexported for ease of interoperability. -pub extern crate bytes; -pub extern crate chrono; -pub extern crate http; -pub extern crate http_body; -pub extern crate query_map; -pub extern crate serde; -#[cfg(not(test))] -pub extern crate serde_json; +#![deny(rust_2018_idioms)] +#[cfg(feature = "http")] +pub use http; +#[cfg(feature = "query_map")] +pub use query_map; mod custom_serde; /// Encodings used in AWS Lambda json event values. pub mod encodings; +#[cfg(feature = "chrono")] pub mod time_window; /// AWS Lambda event definitions. diff --git a/lambda-events/src/time_window.rs b/lambda-events/src/time_window.rs index 9418dc8c..9f035995 100644 --- a/lambda-events/src/time_window.rs +++ b/lambda-events/src/time_window.rs @@ -1,4 +1,5 @@ use chrono::{DateTime, Utc}; +use serde::{Deserialize, Serialize}; use std::collections::HashMap; use crate::custom_serde::deserialize_lambda_map; @@ -65,7 +66,7 @@ pub struct TimeWindowEventResponseProperties { mod test { use super::*; - extern crate serde_json; + use serde_json; #[test] fn test_window_deserializer() { diff --git a/lambda-http/Cargo.toml b/lambda-http/Cargo.toml index 289aec17..1409555e 100644 --- a/lambda-http/Cargo.toml +++ b/lambda-http/Cargo.toml @@ -40,7 +40,7 @@ percent-encoding = "2.2" [dependencies.aws_lambda_events] path = "../lambda-events" -version = "0.9.0" +version = "0.10.0" default-features = false features = ["alb", "apigw"]