From 8165097f9eac033007e74a4dbeb7e4e06d8d8bbc Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Mon, 4 Nov 2024 11:46:46 -0800 Subject: [PATCH 01/11] Removed builders from eventhubs; removed impl Into from eventhubs and AMQP; Fixed time conversion issue with 1-1-0001 --- sdk/core/azure_core_amqp/src/cbs.rs | 15 +- sdk/core/azure_core_amqp/src/connection.rs | 4 +- sdk/core/azure_core_amqp/src/fe2o3/cbs.rs | 14 +- .../azure_core_amqp/src/fe2o3/connection.rs | 2 +- .../azure_core_amqp/src/fe2o3/management.rs | 11 +- .../src/fe2o3/messaging/message_fields.rs | 14 +- .../src/fe2o3/messaging/message_source.rs | 2 +- .../src/fe2o3/messaging/mod.rs | 14 +- sdk/core/azure_core_amqp/src/fe2o3/sender.rs | 4 +- sdk/core/azure_core_amqp/src/fe2o3/value.rs | 56 +- sdk/core/azure_core_amqp/src/management.rs | 6 +- sdk/core/azure_core_amqp/src/messaging.rs | 54 +- sdk/core/azure_core_amqp/src/noop.rs | 17 +- sdk/core/azure_core_amqp/src/receiver.rs | 45 +- sdk/core/azure_core_amqp/src/sender.rs | 14 +- sdk/core/azure_core_amqp/src/session.rs | 4 +- sdk/core/azure_core_amqp/src/value.rs | 43 +- .../azure_messaging_eventhubs/README.md | 28 +- .../eventhubs_partition_properties.rs | 12 +- .../examples/eventhubs_properties.rs | 7 +- .../src/common/mod.rs | 70 ++- .../src/consumer/README.md | 10 +- .../src/consumer/mod.rs | 490 +++++------------- .../azure_messaging_eventhubs/src/lib.rs | 46 +- .../src/producer/batch.rs | 104 +--- .../src/producer/mod.rs | 135 ++--- .../tests/consumer.rs | 79 ++- .../tests/producer.rs | 98 ++-- .../tests/round_trip.rs | 59 ++- 29 files changed, 597 insertions(+), 860 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/cbs.rs b/sdk/core/azure_core_amqp/src/cbs.rs index c66fd76918..f4276faae9 100644 --- a/sdk/core/azure_core_amqp/src/cbs.rs +++ b/sdk/core/azure_core_amqp/src/cbs.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft Corporation. All Rights reserved // Licensed under the MIT license. -// cspell: words amqp sasl +// cspell: words amqp sasl sastoken use azure_core::error::Result; use std::fmt::Debug; @@ -38,6 +38,7 @@ pub trait AmqpClaimsBasedSecurityApis { /// # Parameters /// /// - `path`: A `String` reference representing the AMQP path to be authorized. + /// - `token_type`: An optional `String` representing the type of token used for authorization. This is either "servicebus.windows.net:sastoken" or "jwt". If it is not supplied, "jwt" is assumed. /// - `secret`: An implementor of `Into` representing the secret used for authorization. This is typically a JSON Web token. /// - `expires_on`: A `time::OffsetDateTime` representing the expiration time of the authorization. /// @@ -49,8 +50,9 @@ pub trait AmqpClaimsBasedSecurityApis { /// fn authorize_path( &self, - path: impl Into + Debug, - secret: impl Into, + path: String, + token_type: Option, + secret: String, expires_on: time::OffsetDateTime, ) -> impl std::future::Future>; } @@ -71,12 +73,13 @@ impl<'a> AmqpClaimsBasedSecurity<'a> { impl<'a> AmqpClaimsBasedSecurityApis for AmqpClaimsBasedSecurity<'a> { async fn authorize_path( &self, - path: impl Into + Debug, - secret: impl Into, + path: String, + token_type: Option, + secret: String, expires_on: time::OffsetDateTime, ) -> Result<()> { self.implementation - .authorize_path(path, secret, expires_on) + .authorize_path(path, token_type, secret, expires_on) .await } async fn attach(&self) -> Result<()> { diff --git a/sdk/core/azure_core_amqp/src/connection.rs b/sdk/core/azure_core_amqp/src/connection.rs index c918e3cb81..12f2e75c7d 100644 --- a/sdk/core/azure_core_amqp/src/connection.rs +++ b/sdk/core/azure_core_amqp/src/connection.rs @@ -62,7 +62,7 @@ impl AmqpConnectionOptions { pub trait AmqpConnectionApis { fn open( &self, - name: impl Into, + name: String, url: Url, options: Option, ) -> impl std::future::Future>; @@ -83,7 +83,7 @@ pub struct AmqpConnection { impl AmqpConnectionApis for AmqpConnection { fn open( &self, - name: impl Into, + name: String, url: Url, options: Option, ) -> impl std::future::Future> { diff --git a/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs b/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs index 4c04567416..3519d7b082 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs @@ -67,8 +67,9 @@ impl AmqpClaimsBasedSecurityApis for Fe2o3ClaimsBasedSecurity<'_> { async fn authorize_path( &self, - path: impl Into + Debug, - secret: impl Into, + path: String, + token_type: Option, + secret: String, expires_at: time::OffsetDateTime, ) -> Result<()> { trace!( @@ -77,8 +78,11 @@ impl AmqpClaimsBasedSecurityApis for Fe2o3ClaimsBasedSecurity<'_> { expires_at ); let cbs_token = CbsToken::new( - secret.into(), - "jwt", + secret, + match token_type { + Some(token_type) => token_type, + None => "jwt".to_string(), + }, Some(Timestamp::from( expires_at .to_offset(time::UtcOffset::UTC) @@ -103,7 +107,7 @@ impl AmqpClaimsBasedSecurityApis for Fe2o3ClaimsBasedSecurity<'_> { .lock() .await .borrow_mut() - .put_token(path.into(), cbs_token) + .put_token(path, cbs_token) .await .map_err(AmqpManagement::from)?; Ok(()) diff --git a/sdk/core/azure_core_amqp/src/fe2o3/connection.rs b/sdk/core/azure_core_amqp/src/fe2o3/connection.rs index 4bf96caab9..071e276573 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/connection.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/connection.rs @@ -39,7 +39,7 @@ impl Drop for Fe2o3AmqpConnection { impl AmqpConnectionApis for Fe2o3AmqpConnection { async fn open( &self, - id: impl Into, + id: String, url: Url, options: Option, ) -> Result<()> { diff --git a/sdk/core/azure_core_amqp/src/fe2o3/management.rs b/sdk/core/azure_core_amqp/src/fe2o3/management.rs index e2f26e79d6..381416f3aa 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/management.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/management.rs @@ -9,7 +9,6 @@ use crate::{ session::AmqpSession, value::{AmqpOrderedMap, AmqpValue}, }; - use async_std::sync::Mutex; use azure_core::{ credentials::AccessToken, @@ -40,7 +39,7 @@ impl Drop for Fe2o3AmqpManagement { impl Fe2o3AmqpManagement { pub fn new( session: AmqpSession, - client_node_name: impl Into, + client_node_name: String, access_token: AccessToken, ) -> Result { // Session::get() returns a clone of the underlying session handle. @@ -48,7 +47,7 @@ impl Fe2o3AmqpManagement { Ok(Self { access_token, - client_node_name: client_node_name.into(), + client_node_name, session, management: OnceLock::new(), }) @@ -85,7 +84,7 @@ impl AmqpManagementApis for Fe2o3AmqpManagement { async fn call( &self, - operation_type: impl Into, + operation_type: String, application_properties: AmqpOrderedMap, ) -> Result> { let mut management = self @@ -122,12 +121,12 @@ struct WithApplicationPropertiesRequest<'a> { impl<'a> WithApplicationPropertiesRequest<'a> { pub fn new( - entity_type: impl Into, + entity_type: String, access_token: &'a AccessToken, application_properties: AmqpOrderedMap, ) -> Self { Self { - entity_type: entity_type.into(), + entity_type, access_token, application_properties, } diff --git a/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs b/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs index 35c40367ab..bbd9f9d43a 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs @@ -127,7 +127,7 @@ impl From fn from(application_properties: fe2o3_amqp_types::messaging::ApplicationProperties) -> Self { let mut properties = AmqpOrderedMap::::new(); for (key, value) in application_properties.0 { - properties.insert(key, value); + properties.insert(key, value.into()); } AmqpApplicationProperties(properties) } @@ -278,7 +278,7 @@ impl From for AmqpAnnotations { fn from(annotations: fe2o3_amqp_types::messaging::Annotations) -> Self { let mut amqp_annotations = AmqpOrderedMap::::new(); for (key, value) in annotations { - amqp_annotations.insert(key, value); + amqp_annotations.insert(key.into(), value.into()); } AmqpAnnotations(amqp_annotations) } @@ -484,13 +484,13 @@ fn test_properties_conversion() { .with_content_type("content_type") .with_correlation_id("correlation_id") .with_creation_time(time_now) - .with_group_id("group_id") + .with_group_id("group_id".to_string()) .with_group_sequence(3) .with_message_id("test") - .with_reply_to("reply_to") - .with_reply_to_group_id("reply_to_group_id") - .with_subject("subject") - .with_to("to") + .with_reply_to("reply_to".to_string()) + .with_reply_to_group_id("reply_to_group_id".to_string()) + .with_subject("subject".to_string()) + .with_to("to".to_string()) .with_user_id(vec![1, 2, 3]) .build(); diff --git a/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_source.rs b/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_source.rs index e6e1080a15..2e7613bc09 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_source.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_source.rs @@ -222,7 +222,7 @@ fn message_source_conversion_fe2o3_amqp() { #[test] fn message_source_conversion_amqp_fe2o3() { let amqp_source = AmqpSource::builder() - .with_address("test") + .with_address("test".to_string()) .with_durable(TerminusDurability::UnsettledState) .with_expiry_policy(TerminusExpiryPolicy::SessionEnd) .with_timeout(95) diff --git a/sdk/core/azure_core_amqp/src/fe2o3/messaging/mod.rs b/sdk/core/azure_core_amqp/src/fe2o3/messaging/mod.rs index 7fe500685d..0a3a8b99f5 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/messaging/mod.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/messaging/mod.rs @@ -521,8 +521,8 @@ mod tests { std::time::UNIX_EPOCH + std::time::Duration::from_millis(timestamp as u64); let amqp_message = AmqpMessage::builder() - .add_application_property("abc", "23 skiddoo") - .add_application_property("What?", 29.5) + .add_application_property("abc".to_string(), "23 skiddoo") + .add_application_property("What?".to_string(), 29.5) .with_body(AmqpValue::from("hello")) .with_properties( AmqpMessageProperties::builder() @@ -531,13 +531,13 @@ mod tests { .with_content_type(AmqpSymbol::from("text/plain")) .with_correlation_id("abc") .with_creation_time(timestamp) - .with_group_id(AmqpSymbol::from("group")) + .with_group_id("group".to_string()) .with_group_sequence(5) .with_message_id("message") - .with_reply_to(AmqpSymbol::from("reply")) - .with_reply_to_group_id(AmqpSymbol::from("reply_group")) - .with_subject(AmqpSymbol::from("subject")) - .with_to(AmqpSymbol::from("to")) + .with_reply_to("reply".to_string()) + .with_reply_to_group_id("reply_group".to_string()) + .with_subject("subject".to_string()) + .with_to("to".to_string()) .with_user_id(vec![39, 20, 54]) .build(), ) diff --git a/sdk/core/azure_core_amqp/src/fe2o3/sender.rs b/sdk/core/azure_core_amqp/src/fe2o3/sender.rs index 09bb880bfe..b4d5352866 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/sender.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/sender.rs @@ -24,7 +24,7 @@ impl AmqpSenderApis for Fe2o3AmqpSender { async fn attach( &self, session: &AmqpSession, - name: impl Into, + name: String, target: impl Into, options: Option, ) -> Result<()> { @@ -63,7 +63,7 @@ impl AmqpSenderApis for Fe2o3AmqpSender { } } let sender = session_builder - .name(name.into()) + .name(name) .target(target.into()) .attach(session.implementation.get()?.lock().await.borrow_mut()) .await diff --git a/sdk/core/azure_core_amqp/src/fe2o3/value.rs b/sdk/core/azure_core_amqp/src/fe2o3/value.rs index 24eced4a12..c3b1495fc0 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/value.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/value.rs @@ -36,23 +36,31 @@ impl From for fe2o3_amqp_types::primitives::Symbol { } } +// Number of milliseconds between the Unix epoch (1/1/1970) and year 1 CE. +// This is the lowest value that can be represented by an AMQP timestamp. +const CE_ZERO_MILLISECONDS: i64 = -62_135_596_800_000; + impl From for AmqpTimestamp { fn from(timestamp: fe2o3_amqp_types::primitives::Timestamp) -> Self { AmqpTimestamp( - std::time::UNIX_EPOCH - + std::time::Duration::from_millis(timestamp.milliseconds() as u64), + std::time::UNIX_EPOCH.checked_add(std::time::Duration::from_millis( + timestamp.milliseconds() as u64, + )), ) } } impl From for fe2o3_amqp_types::primitives::Timestamp { fn from(timestamp: AmqpTimestamp) -> Self { - let t = timestamp - .0 - .duration_since(UNIX_EPOCH) - .expect("Could not convert timestamp to time since unix epoch") - .as_millis(); - fe2o3_amqp_types::primitives::Timestamp::from_milliseconds(t as i64) + if let Some(t) = timestamp.0 { + let t = t + .duration_since(UNIX_EPOCH) + .expect("Could not convert timestamp to time since unix epoch") + .as_millis(); + fe2o3_amqp_types::primitives::Timestamp::from_milliseconds(t as i64) + } else { + fe2o3_amqp_types::primitives::Timestamp::from_milliseconds(CE_ZERO_MILLISECONDS) + } } } @@ -239,9 +247,9 @@ impl From for AmqpValue { AmqpValue::List(AmqpList(l)) } fe2o3_amqp_types::primitives::Value::Map(m) => { - let mut map = AmqpOrderedMap::new(); + let mut map: AmqpOrderedMap = AmqpOrderedMap::new(); for (k, v) in m { - map.insert(k, v); + map.insert(k.into(), v.into()); } AmqpValue::Map(map) } @@ -329,13 +337,19 @@ impl PartialEq for fe2o3_amqp_types::primitives::Value { } AmqpValue::Char(c) => self == &fe2o3_amqp_types::primitives::Value::Char(*c), AmqpValue::TimeStamp(t) => { - let t: u64 = - t.0.duration_since(UNIX_EPOCH) + if let Some(t) = t.0 { + let t: u64 = t + .duration_since(UNIX_EPOCH) .expect("Could not convert timestamp into unix epoch") .as_millis() as u64; - self == &fe2o3_amqp_types::primitives::Value::Timestamp( - Timestamp::from_milliseconds(t as i64), - ) + self == &fe2o3_amqp_types::primitives::Value::Timestamp( + Timestamp::from_milliseconds(t as i64), + ) + } else { + self == &fe2o3_amqp_types::primitives::Value::Timestamp( + Timestamp::from_milliseconds(CE_ZERO_MILLISECONDS), + ) + } } AmqpValue::Uuid(u) => self == &fe2o3_amqp_types::primitives::Value::Uuid((*u).into()), AmqpValue::Binary(b) => { @@ -386,15 +400,11 @@ impl PartialEq for AmqpValue { } } -impl From for AmqpOrderedMap -where - K: PartialEq + From + Clone + Default, - V: From + Clone + Default, -{ +impl From for AmqpOrderedMap { fn from(fields: fe2o3_amqp_types::definitions::Fields) -> Self { - let mut map = AmqpOrderedMap::new(); + let mut map: AmqpOrderedMap = AmqpOrderedMap::new(); for (k, v) in fields { - map.insert(k, v); + map.insert(k.into(), v.into()); } map } @@ -417,7 +427,7 @@ impl // Convert the OrderedMap to AmqpOrderedMap let mut amqp_ordered_map = AmqpOrderedMap::new(); for (key, value) in value.into_iter() { - amqp_ordered_map.insert(key, value); + amqp_ordered_map.insert(key, value.into()); } amqp_ordered_map } diff --git a/sdk/core/azure_core_amqp/src/management.rs b/sdk/core/azure_core_amqp/src/management.rs index 450fb34ab1..a1b52c1074 100644 --- a/sdk/core/azure_core_amqp/src/management.rs +++ b/sdk/core/azure_core_amqp/src/management.rs @@ -22,7 +22,7 @@ pub trait AmqpManagementApis { #[allow(unused_variables)] fn call( &self, - operation_type: impl Into, + operation_type: String, application_properties: AmqpOrderedMap, ) -> impl std::future::Future>>; } @@ -41,7 +41,7 @@ impl AmqpManagementApis for AmqpManagement { } async fn call( &self, - operation_type: impl Into, + operation_type: String, application_properties: AmqpOrderedMap, ) -> Result> { self.implementation @@ -53,7 +53,7 @@ impl AmqpManagementApis for AmqpManagement { impl AmqpManagement { pub fn new( session: AmqpSession, - client_node_name: impl Into, + client_node_name: String, access_token: AccessToken, ) -> Result { Ok(Self { diff --git a/sdk/core/azure_core_amqp/src/messaging.rs b/sdk/core/azure_core_amqp/src/messaging.rs index db98a5e898..15bb69c693 100644 --- a/sdk/core/azure_core_amqp/src/messaging.rs +++ b/sdk/core/azure_core_amqp/src/messaging.rs @@ -1033,9 +1033,9 @@ where V: Into, { fn from(vec: Vec<(K, V)>) -> Self { - let mut map = AmqpOrderedMap::new(); + let mut map: AmqpOrderedMap = AmqpOrderedMap::new(); for (k, v) in vec { - map.insert(k, v); + map.insert(k.into(), v.into()); } AmqpAnnotations(map) } @@ -1049,8 +1049,8 @@ impl AmqpApplicationProperties { AmqpApplicationProperties(AmqpOrderedMap::new()) } - pub fn insert(&mut self, key: impl Into, value: impl Into) { - self.0.insert(key.into(), value.into()); + pub fn insert(&mut self, key: String, value: impl Into) { + self.0.insert(key, value.into()); } } @@ -1282,8 +1282,8 @@ pub mod builders { source: Default::default(), } } - pub fn with_address(mut self, address: impl Into) -> Self { - self.source.address = Some(address.into()); + pub fn with_address(mut self, address: String) -> Self { + self.source.address = Some(address); self } pub fn with_durable(mut self, durable: TerminusDurability) -> Self { @@ -1364,8 +1364,8 @@ pub mod builders { target: Default::default(), } } - pub fn with_address(mut self, address: impl Into) -> Self { - self.target.address = Some(address.into()); + pub fn with_address(mut self, address: String) -> Self { + self.target.address = Some(address); self } pub fn with_durable(mut self, durable: TerminusDurability) -> Self { @@ -1453,16 +1453,16 @@ pub mod builders { self.properties.user_id = Some(user_id.into()); self } - pub fn with_to(mut self, to: impl Into) -> Self { - self.properties.to = Some(to.into()); + pub fn with_to(mut self, to: String) -> Self { + self.properties.to = Some(to); self } - pub fn with_subject(mut self, subject: impl Into) -> Self { - self.properties.subject = Some(subject.into()); + pub fn with_subject(mut self, subject: String) -> Self { + self.properties.subject = Some(subject); self } - pub fn with_reply_to(mut self, reply_to: impl Into) -> Self { - self.properties.reply_to = Some(reply_to.into()); + pub fn with_reply_to(mut self, reply_to: String) -> Self { + self.properties.reply_to = Some(reply_to); self } pub fn with_correlation_id(mut self, correlation_id: impl Into) -> Self { @@ -1488,16 +1488,16 @@ pub mod builders { self.properties.creation_time = Some(creation_time.into()); self } - pub fn with_group_id(mut self, group_id: impl Into) -> Self { - self.properties.group_id = Some(group_id.into()); + pub fn with_group_id(mut self, group_id: String) -> Self { + self.properties.group_id = Some(group_id); self } pub fn with_group_sequence(mut self, group_sequence: u32) -> Self { self.properties.group_sequence = Some(group_sequence); self } - pub fn with_reply_to_group_id(mut self, reply_to_group_id: impl Into) -> Self { - self.properties.reply_to_group_id = Some(reply_to_group_id.into()); + pub fn with_reply_to_group_id(mut self, reply_to_group_id: String) -> Self { + self.properties.reply_to_group_id = Some(reply_to_group_id); self } } @@ -1560,14 +1560,14 @@ pub mod builders { } pub fn add_application_property( mut self, - key: impl Into, + key: String, value: impl Into, ) -> Self { if let Some(application_properties) = &mut self.message.application_properties { - application_properties.0.insert(key.into(), value.into()); + application_properties.0.insert(key, value.into()); } else { let mut application_properties = AmqpOrderedMap::new(); - application_properties.insert(key.into(), value.into()); + application_properties.insert(key, value.into()); self.message.application_properties = Some(AmqpApplicationProperties(application_properties)); } @@ -1654,16 +1654,16 @@ mod tests { .with_message_id(test_uuid1) .with_user_id(vec![1, 2, 3]) .with_to("destination".to_string()) - .with_subject("subject") + .with_subject("subject".to_string()) .with_reply_to("reply_to".to_string()) .with_correlation_id(test_uuid2) .with_content_type("content_type") .with_content_encoding(AmqpSymbol::from("content_encoding")) .with_absolute_expiry_time(time_now) .with_creation_time(time_now) - .with_group_id("group_id") + .with_group_id("group_id".to_string()) .with_group_sequence(1) - .with_reply_to_group_id("reply_to_group_id") + .with_reply_to_group_id("reply_to_group_id".to_string()) .build(); assert_eq!(properties.message_id, Some(test_uuid1.into())); @@ -1706,7 +1706,7 @@ mod tests { assert_eq!(message.body, AmqpMessageBody::Binary(vec![vec![1, 2, 3]])); assert_eq!(message.header, Some(AmqpMessageHeader::builder().build())); let mut properties = AmqpApplicationProperties::new(); - properties.insert("key", AmqpValue::from(123)); + properties.insert("key".to_string(), AmqpValue::from(123)); assert_eq!(message.application_properties, Some(properties)); assert_eq!(message.message_annotations, Some(AmqpAnnotations::new())); assert_eq!(message.delivery_annotations, Some(AmqpAnnotations::new())); @@ -1781,7 +1781,7 @@ mod tests { #[test] fn test_amqp_source_builder() { let source = AmqpSource::builder() - .with_address("address") + .with_address("address".to_string()) .with_durable(TerminusDurability::Configuration) .with_expiry_policy(TerminusExpiryPolicy::ConnectionClose) .with_timeout(10) @@ -1811,7 +1811,7 @@ mod tests { #[test] fn test_amqp_target_builder() { let target = AmqpTarget::builder() - .with_address("address") + .with_address("address".to_string()) .with_durable(TerminusDurability::Configuration) .with_expiry_policy(TerminusExpiryPolicy::ConnectionClose) .with_timeout(10) diff --git a/sdk/core/azure_core_amqp/src/noop.rs b/sdk/core/azure_core_amqp/src/noop.rs index cd84163fbd..2d4da8670b 100644 --- a/sdk/core/azure_core_amqp/src/noop.rs +++ b/sdk/core/azure_core_amqp/src/noop.rs @@ -44,7 +44,7 @@ impl NoopAmqpConnection { impl AmqpConnectionApis for NoopAmqpConnection { async fn open( &self, - name: impl Into, + name: String, url: azure_core::Url, options: Option, ) -> Result<()> { @@ -101,8 +101,9 @@ impl<'a> AmqpClaimsBasedSecurityApis for NoopAmqpClaimsBasedSecurity<'a> { } async fn authorize_path( &self, - path: impl Into + std::fmt::Debug, - secret: impl Into, + path: String, + token_type: Option, + secret: String, expires_on: time::OffsetDateTime, ) -> Result<()> { unimplemented!() @@ -110,11 +111,7 @@ impl<'a> AmqpClaimsBasedSecurityApis for NoopAmqpClaimsBasedSecurity<'a> { } impl NoopAmqpManagement { - pub fn new( - session: AmqpSession, - name: impl Into, - access_token: AccessToken, - ) -> Result { + pub fn new(session: AmqpSession, name: String, access_token: AccessToken) -> Result { Ok(Self {}) } } @@ -129,7 +126,7 @@ impl AmqpManagementApis for NoopAmqpManagement { async fn call( &self, - operation_type: impl Into, + operation_type: String, application_properties: AmqpOrderedMap, ) -> Result> { unimplemented!(); @@ -146,7 +143,7 @@ impl AmqpSenderApis for NoopAmqpSender { async fn attach( &self, session: &AmqpSession, - name: impl Into, + name: String, target: impl Into, options: Option, ) -> Result<()> { diff --git a/sdk/core/azure_core_amqp/src/receiver.rs b/sdk/core/azure_core_amqp/src/receiver.rs index fec49189ed..ab8f7e4f67 100644 --- a/sdk/core/azure_core_amqp/src/receiver.rs +++ b/sdk/core/azure_core_amqp/src/receiver.rs @@ -130,7 +130,7 @@ pub mod builders { options: Default::default(), } } - #[allow(dead_code)] + pub fn with_receiver_settle_mode( mut self, receiver_settle_mode: ReceiverSettleMode, @@ -138,17 +138,17 @@ pub mod builders { self.options.receiver_settle_mode = Some(receiver_settle_mode); self } - #[allow(dead_code)] + pub fn with_target(mut self, target: impl Into) -> Self { self.options.target = Some(target.into()); self } - #[allow(dead_code)] - pub fn with_name(mut self, name: impl Into) -> Self { - self.options.name = Some(name.into()); + + pub fn with_name(mut self, name: String) -> Self { + self.options.name = Some(name); self } - #[allow(dead_code)] + pub fn with_properties( mut self, properties: impl Into>, @@ -159,8 +159,9 @@ pub mod builders { self.options.properties = Some(properties_map); self } - pub fn add_property(mut self, key: impl Into, value: impl Into) -> Self { - let key = AmqpSymbol::from(key.into()); + + pub fn add_property(mut self, key: String, value: impl Into) -> Self { + let key = AmqpSymbol::from(key); let value = value.into(); if let Some(properties) = self.options.properties.as_mut() { properties.insert(key, value); @@ -198,7 +199,11 @@ mod tests { let receiver_options = AmqpReceiverOptions::builder() .with_receiver_settle_mode(ReceiverSettleMode::Second) .with_receiver_settle_mode(ReceiverSettleMode::First) - .with_target(AmqpTarget::builder().with_address("address").build()) + .with_target( + AmqpTarget::builder() + .with_address("address".to_string()) + .build(), + ) .with_properties(properties) .build(); @@ -208,9 +213,9 @@ mod tests { ); assert!(receiver_options.properties.is_some()); let properties = receiver_options.properties.clone().unwrap(); - assert!(properties.contains_key("key")); + assert!(properties.contains_key("key".into())); assert_eq!( - *properties.get("key").unwrap(), + *properties.get("key".into()).unwrap(), AmqpValue::String("value".to_string()) ); } @@ -218,7 +223,11 @@ mod tests { #[test] fn test_amqp_receiver_options_builder_with_target() { let receiver_options = AmqpReceiverOptions::builder() - .with_target(AmqpTarget::builder().with_address("test_address").build()) + .with_target( + AmqpTarget::builder() + .with_address("test_address".to_string()) + .build(), + ) .build(); assert!(receiver_options.target.is_some()); @@ -231,7 +240,7 @@ mod tests { #[test] fn test_amqp_receiver_options_builder_with_name() { let receiver_options = AmqpReceiverOptions::builder() - .with_name("test_receiver") + .with_name("test_receiver".into()) .build(); assert!(receiver_options.name.is_some()); @@ -270,8 +279,12 @@ mod tests { let receiver_options = AmqpReceiverOptions::builder() .with_receiver_settle_mode(ReceiverSettleMode::First) - .with_target(AmqpTarget::builder().with_address("combo_address").build()) - .with_name("combo_name") + .with_target( + AmqpTarget::builder() + .with_address("combo_address".to_string()) + .build(), + ) + .with_name("combo_name".into()) .with_properties(properties.clone()) .with_credit_mode(ReceiverCreditMode::Manual) .with_auto_accept(false) @@ -290,7 +303,7 @@ mod tests { assert!(receiver_options.properties.is_some()); let properties_option = receiver_options.properties.unwrap(); assert_eq!( - *properties_option.get("combo_key").unwrap(), + *properties_option.get("combo_key".into()).unwrap(), AmqpValue::String("combo_value".to_string()) ); assert_eq!( diff --git a/sdk/core/azure_core_amqp/src/sender.rs b/sdk/core/azure_core_amqp/src/sender.rs index 4379480b31..4bf336b8c9 100644 --- a/sdk/core/azure_core_amqp/src/sender.rs +++ b/sdk/core/azure_core_amqp/src/sender.rs @@ -36,7 +36,7 @@ pub trait AmqpSenderApis { fn attach( &self, session: &AmqpSession, - name: impl Into, + name: String, target: impl Into, options: Option, ) -> impl std::future::Future>; @@ -58,7 +58,7 @@ impl AmqpSenderApis for AmqpSender { async fn attach( &self, session: &AmqpSession, - name: impl Into, + name: String, target: impl Into, options: Option, ) -> Result<()> { @@ -215,7 +215,11 @@ mod tests { .with_sender_settle_mode(SenderSettleMode::Mixed) .with_receiver_settle_mode(ReceiverSettleMode::Second) .with_receiver_settle_mode(ReceiverSettleMode::First) - .with_source(AmqpSource::builder().with_address("address").build()) + .with_source( + AmqpSource::builder() + .with_address("address".to_string()) + .build(), + ) .with_offered_capabilities(vec!["capability".into()]) .with_desired_capabilities(vec!["capability".into()]) .with_properties(properties) @@ -241,9 +245,9 @@ mod tests { ); assert!(sender_options.properties.is_some()); let properties = sender_options.properties.clone().unwrap(); - assert!(properties.contains_key("key")); + assert!(properties.contains_key("key".into())); assert_eq!( - *properties.get("key").unwrap(), + *properties.get("key".into()).unwrap(), AmqpValue::String("value".to_string()) ); diff --git a/sdk/core/azure_core_amqp/src/session.rs b/sdk/core/azure_core_amqp/src/session.rs index 737ffe3f23..6c770140a7 100644 --- a/sdk/core/azure_core_amqp/src/session.rs +++ b/sdk/core/azure_core_amqp/src/session.rs @@ -192,9 +192,9 @@ mod tests { ); assert!(session_options.properties.is_some()); let properties = session_options.properties.clone().unwrap(); - assert!(properties.contains_key("key")); + assert!(properties.contains_key("key".into())); assert_eq!( - *properties.get("key").unwrap(), + *properties.get("key".into()).unwrap(), AmqpValue::String("value".to_string()) ); diff --git a/sdk/core/azure_core_amqp/src/value.rs b/sdk/core/azure_core_amqp/src/value.rs index 6b2099acbe..9d8a4a5c22 100644 --- a/sdk/core/azure_core_amqp/src/value.rs +++ b/sdk/core/azure_core_amqp/src/value.rs @@ -76,12 +76,17 @@ impl From> for AmqpList { } } +/// AMQP Timestamp. Number of milliseconds since UNIX_EPOCH. +/// +/// NOTE: This can also contain the value of -62_135_596_800_000 which is +/// January 1, 0001 represented as the number of milliseconds *BEFORE* the UNIX_EPOCH. +/// This time cannot be expressed as a SystemTime. #[derive(Debug, PartialEq, Clone)] -pub struct AmqpTimestamp(pub std::time::SystemTime); +pub struct AmqpTimestamp(pub Option); impl From for AmqpTimestamp { fn from(v: std::time::SystemTime) -> Self { - AmqpTimestamp(v) + AmqpTimestamp(Some(v)) } } @@ -252,18 +257,14 @@ where Self { inner: Vec::new() } } - pub fn insert(&mut self, key: impl Into, value: impl Into) { - self.inner.push((key.into(), value.into())); + pub fn insert(&mut self, key: K, value: V) { + self.inner.push((key, value)); } - pub fn get(&self, key: impl Into + Clone) -> Option<&V> { - self.inner.iter().find_map(|(k, v)| { - if *k == key.clone().into() { - Some(v) - } else { - None - } - }) + pub fn get(&self, key: K) -> Option<&V> { + self.inner + .iter() + .find_map(|(k, v)| if *k == key.clone() { Some(v) } else { None }) } pub fn len(&self) -> usize { @@ -279,8 +280,8 @@ where Some(self.inner.remove(index).1) } - pub fn contains_key(&self, key: impl Into + Clone) -> bool { - self.inner.iter().any(|(k, _)| *k == key.clone().into()) + pub fn contains_key(&self, key: K) -> bool { + self.inner.iter().any(|(k, _)| *k == key.clone()) } pub fn iter(&self) -> impl Iterator + '_ { @@ -472,7 +473,7 @@ mod tests { let v10 = AmqpValue::Float(9.0); let v11 = AmqpValue::Double(10.0); let v12 = AmqpValue::Char('a'); - let v13 = AmqpValue::TimeStamp(AmqpTimestamp(timestamp)); + let v13 = AmqpValue::TimeStamp(AmqpTimestamp(Some(timestamp))); let v14 = AmqpValue::Uuid(uuid); let v15 = AmqpValue::Binary(vec![1, 2, 3]); let v16 = AmqpValue::String("hello".to_string()); @@ -502,7 +503,7 @@ mod tests { assert_eq!(v10, AmqpValue::Float(9.0)); assert_eq!(v11, AmqpValue::Double(10.0)); assert_eq!(v12, AmqpValue::Char('a')); - assert_eq!(v13, AmqpValue::TimeStamp(AmqpTimestamp(timestamp))); + assert_eq!(v13, AmqpValue::TimeStamp(AmqpTimestamp(Some(timestamp)))); assert_eq!(v14, AmqpValue::Uuid(uuid)); assert_eq!(v15, AmqpValue::Binary(vec![1, 2, 3])); assert_eq!(v16, AmqpValue::String("hello".to_string())); @@ -566,7 +567,7 @@ mod tests { test_conversion!( AmqpTimestamp, TimeStamp, - AmqpTimestamp(std::time::SystemTime::now()) + AmqpTimestamp(Some(std::time::SystemTime::now())) ); test_conversion!(Uuid, Uuid, Uuid::new_v4()); test_conversion!(Vec, Binary, vec![1, 2, 3]); @@ -723,17 +724,17 @@ mod tests { // Test AmqpValue::TimeStamp let timestamp = std::time::SystemTime::now(); - let timestamp_value: AmqpValue = AmqpValue::TimeStamp(AmqpTimestamp(timestamp)); + let timestamp_value: AmqpValue = AmqpValue::TimeStamp(AmqpTimestamp(Some(timestamp))); assert_eq!( timestamp_value, - AmqpValue::TimeStamp(AmqpTimestamp(timestamp)) + AmqpValue::TimeStamp(AmqpTimestamp(Some(timestamp))) ); assert_eq!( - AmqpValue::TimeStamp(AmqpTimestamp(timestamp)), + AmqpValue::TimeStamp(AmqpTimestamp(Some(timestamp))), timestamp_value ); let timestamp_val: AmqpTimestamp = timestamp_value.into(); - assert_eq!(timestamp_val, AmqpTimestamp(timestamp)); + assert_eq!(timestamp_val, AmqpTimestamp(Some(timestamp))); // Test AmqpValue::Uuid let uuid = Uuid::new_v4(); diff --git a/sdk/eventhubs/azure_messaging_eventhubs/README.md b/sdk/eventhubs/azure_messaging_eventhubs/README.md index c09ed2f3b3..419396a44b 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/README.md +++ b/sdk/eventhubs/azure_messaging_eventhubs/README.md @@ -172,10 +172,11 @@ async fn send_events() { host, eventhub.clone(), credential, - azure_messaging_eventhubs::producer::ProducerClientOptions::builder() - .with_application_id("test_create_batch") - .build(), - ); + Some(azure_messaging_eventhubs::producer::ProducerClientOptions{ + application_id: Some("test_create_batch".to_string()), + ..Default::default() + }), + ); client.open().await.unwrap(); { let mut batch = client.create_batch(None).await.unwrap(); @@ -207,9 +208,9 @@ async fn receive_events() { None, credential, Some( - azure_messaging_eventhubs::consumer::ConsumerClientOptions::builder() - .with_application_id("receive_lots_of_events") - .build(), + azure_messaging_eventhubs::consumer::ConsumerClientOptions{ + application_id: Some("receive_lots_of_events".to_string()), + ..Default::default()} ), ); @@ -217,13 +218,14 @@ async fn receive_events() { let event_stream = client .receive_events_on_partition( - "0", + "0".to_string(), Some( - azure_messaging_eventhubs::consumer::ReceiveOptions::builder() - .with_start_position(azure_messaging_eventhubs::consumer::StartPosition::builder().with_earliest_location().build()) - .build(), - ), - ) + azure_messaging_eventhubs::consumer::ReceiveOptions{ + start_position: Some(azure_messaging_eventhubs::consumer::StartPosition{ + location: azure_messaging_eventhubs::consumer::StartLocation::Earliest, + ..Default::default()}), + ..Default::default()}, + )) .await; pin_mut!(event_stream); // Needed for iteration. diff --git a/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_partition_properties.rs b/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_partition_properties.rs index a37efe3834..005f3a1cde 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_partition_properties.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_partition_properties.rs @@ -23,9 +23,10 @@ async fn main() -> Result<()> { host, eventhub.clone(), credential, - ProducerClientOptions::builder() - .with_application_id("test_get_properties") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_get_properties".to_string()), + ..Default::default() + }), ); let result = client.open().await; info!("Open result: {:?}", result); @@ -37,7 +38,10 @@ async fn main() -> Result<()> { println!("Eventhub Properties for: {eventhub} {:?}", properties); for partition in properties.partition_ids.iter() { - let partition_properties = client.get_partition_properties(partition).await.unwrap(); + let partition_properties = client + .get_partition_properties(partition.clone()) + .await + .unwrap(); println!( "Partition Properties for: {partition} {:?}", partition_properties diff --git a/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_properties.rs b/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_properties.rs index f3ecf6f39c..3415109737 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_properties.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/examples/eventhubs_properties.rs @@ -24,9 +24,10 @@ async fn main() -> Result<()> { host, eventhub.clone(), credential, - ProducerClientOptions::builder() - .with_application_id("test_get_properties") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_get_properties".to_string()), + ..Default::default() + }), ); let result = client.open().await; info!("Open result: {:?}", result); diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs index ba1e8ebee1..cabfdd63a2 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs @@ -20,34 +20,50 @@ pub(crate) struct ManagementInstance { pub management: AmqpManagement, } +const EVENTHUB_ENTITY_TYPE: &str = "com.microsoft:eventhub"; +const PARTITION_ENTITY_TYPE: &str = "com.microsoft:partition"; + +const EVENTHUB_PROPERTY_PARTITION_COUNT: &str = "partition_count"; +const EVENTHUB_PROPERTY_PARTITION_IDS: &str = "partition_ids"; +const EVENTHUB_PROPERTY_NAME: &str = "name"; +const EVENTHUB_PROPERTY_PARTITION: &str = "partition"; +const EVENTHUB_PROPERTY_CREATED_AT: &str = "created_at"; + +const EVENTHUB_PARTITION_PROPERTIES_TYPE: &str = "type"; +const EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER_EPOCH: &str = + "last_enqueued_sequence_number_epoch"; +const EVENTHUB_PARTITION_PROPERTIES_BEGIN_SEQUENCE_NUMBER: &str = "begin_sequence_number"; +const EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER: &str = + "last_enqueued_sequence_number"; +const EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_OFFSET: &str = "last_enqueued_offset"; +const EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_TIME_UTC: &str = "last_enqueued_time_utc"; +const EVENTHUB_PARTITION_PROPERTIES_IS_EMPTY: &str = "is_partition_empty"; + impl ManagementInstance { pub fn new(management: AmqpManagement) -> Self { Self { management } } - pub async fn get_eventhub_properties( - &self, - eventhub: impl Into, - ) -> Result { + pub async fn get_eventhub_properties(&self, eventhub: String) -> Result { let mut application_properties: AmqpOrderedMap = AmqpOrderedMap::new(); - application_properties.insert("name", eventhub.into()); + application_properties.insert(EVENTHUB_PROPERTY_NAME.to_string(), eventhub.into()); let response = self .management - .call("com.microsoft:eventhub", application_properties) + .call(EVENTHUB_ENTITY_TYPE.to_string(), application_properties) .await?; - if !response.contains_key("partition_count") { + if !response.contains_key(EVENTHUB_PROPERTY_PARTITION_COUNT.to_string()) { return Err(ErrorKind::InvalidManagementResponse.into()); } let name: String = response - .get("name") + .get(EVENTHUB_PROPERTY_NAME.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(); - let created_at: SystemTime = Into::::into( + let created_at: Option = Into::::into( response - .get("created_at") + .get(EVENTHUB_PROPERTY_CREATED_AT.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone(), ) @@ -56,7 +72,7 @@ impl ManagementInstance { // Into::::into(response.get("partition_count".to_string()).ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))?.clone()); let partition_ids = response - .get("partition_ids") + .get(EVENTHUB_PROPERTY_PARTITION_IDS.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))?; let partition_ids = match partition_ids { @@ -78,63 +94,63 @@ impl ManagementInstance { pub async fn get_eventhub_partition_properties( &self, - eventhub: impl Into, - partition_id: impl Into, + eventhub: String, + partition_id: String, ) -> Result { - let partition_id: String = partition_id.into(); - let mut application_properties: AmqpOrderedMap = AmqpOrderedMap::new(); - application_properties.insert("name", eventhub.into()); - application_properties.insert("partition", partition_id); + application_properties.insert(EVENTHUB_PROPERTY_NAME.to_string(), eventhub.into()); + application_properties.insert(EVENTHUB_PROPERTY_PARTITION.to_string(), partition_id.into()); let response = self .management - .call("com.microsoft:partition", application_properties) + .call(PARTITION_ENTITY_TYPE.to_string(), application_properties) .await?; // Look for the required response properties - if !response.contains_key("type") - || !response.contains_key("last_enqueued_sequence_number_epoch") + if !response.contains_key(EVENTHUB_PARTITION_PROPERTIES_TYPE.to_string()) + || !response.contains_key( + EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER_EPOCH.to_string(), + ) { return Err(ErrorKind::InvalidManagementResponse.into()); } Ok(EventHubPartitionProperties { beginning_sequence_number: response - .get("begin_sequence_number") + .get(EVENTHUB_PARTITION_PROPERTIES_BEGIN_SEQUENCE_NUMBER.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), id: response - .get("partition") + .get(EVENTHUB_PROPERTY_PARTITION.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), eventhub: response - .get("name") + .get(EVENTHUB_PROPERTY_NAME.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_sequence_number: response - .get("last_enqueued_sequence_number") + .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_offset: response - .get("last_enqueued_offset") + .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_OFFSET.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_time_utc: Into::::into( response - .get("last_enqueued_time_utc".to_string()) + .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_TIME_UTC.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone(), ) .0, is_empty: response - .get("is_partition_empty") + .get(EVENTHUB_PARTITION_PROPERTIES_IS_EMPTY.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/README.md b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/README.md index 597c8d82f2..447ff9be8d 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/README.md +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/README.md @@ -16,7 +16,7 @@ use azure_messaging_eventhubs::consumer::ConsumerClient; use azure_identity::{DefaultAzureCredential, TokenCredentialOptions}; let my_credential = DefaultAzureCredential::new().unwrap(); -let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); +let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); ``` ### Opening a connection to the Event Hub @@ -28,7 +28,7 @@ use azure_identity::{DefaultAzureCredential, TokenCredentialOptions}; #[tokio::main] async fn main() { let my_credential = DefaultAzureCredential::new().unwrap(); - let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); let result = consumer.open().await; @@ -54,7 +54,7 @@ use azure_identity::{DefaultAzureCredential, TokenCredentialOptions}; #[tokio::main] async fn main() { let my_credential = DefaultAzureCredential::new().unwrap(); - let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); consumer.open().await.unwrap(); @@ -83,13 +83,13 @@ use async_std::stream::StreamExt; #[tokio::main] async fn main() { let my_credential = DefaultAzureCredential::new().unwrap(); - let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); let partition_id = "0"; let options = None; consumer.open().await.unwrap(); - let event_stream = consumer.receive_events_on_partition(partition_id, options).await; + let event_stream = consumer.receive_events_on_partition(partition_id.to_string(), options).await; tokio::pin!(event_stream); while let Some(event_result) = event_stream.next().await { diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs index 7214a439ab..ba5b3d639e 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs @@ -32,6 +32,7 @@ use azure_core_amqp::{ use futures::stream::Stream; use std::{ collections::HashMap, + default::Default, fmt::Debug, sync::{Arc, OnceLock}, }; @@ -76,24 +77,21 @@ impl ConsumerClient { /// use azure_identity::{DefaultAzureCredential, TokenCredentialOptions}; /// /// let my_credential = DefaultAzureCredential::new()?; - /// let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// # Ok(())} /// ``` #[tracing::instrument] pub fn new( - fully_qualified_namespace: impl Into + Debug, - eventhub_name: impl Into + Debug, + fully_qualified_namespace: String, + eventhub_name: String, consumer_group: Option, credential: Arc, options: Option, ) -> Self { - let eventhub_name = eventhub_name.into(); let consumer_group = consumer_group.unwrap_or("$Default".into()); let url = format!( "amqps://{}/{}/ConsumerGroups/{}", - fully_qualified_namespace.into(), - eventhub_name, - consumer_group + fully_qualified_namespace, eventhub_name, consumer_group ); Self { options: options.unwrap_or_default(), @@ -125,7 +123,7 @@ impl ConsumerClient { /// #[tokio::main] /// async fn main() { /// let my_credential = DefaultAzureCredential::new().unwrap(); - /// let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// /// let result = consumer.open().await; /// @@ -167,7 +165,7 @@ impl ConsumerClient { /// #[tokio::main] /// async fn main() { /// let my_credential = DefaultAzureCredential::new().unwrap(); - /// let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// /// consumer.open().await.unwrap(); /// @@ -211,7 +209,7 @@ impl ConsumerClient { /// /// # Example /// - /// ``` no_run + /// ```no_run /// use azure_messaging_eventhubs::consumer::ConsumerClient; /// use azure_identity::{DefaultAzureCredential, TokenCredentialOptions}; /// use async_std::stream::StreamExt; @@ -219,13 +217,13 @@ impl ConsumerClient { /// #[tokio::main] /// async fn main() { /// let my_credential = DefaultAzureCredential::new().unwrap(); - /// let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// let partition_id = "0"; /// let options = None; /// /// consumer.open().await.unwrap(); /// - /// let event_stream = consumer.receive_events_on_partition(partition_id, options).await; + /// let event_stream = consumer.receive_events_on_partition(partition_id.to_string(), options).await; /// /// tokio::pin!(event_stream); /// while let Some(event_result) = event_stream.next().await { @@ -245,10 +243,9 @@ impl ConsumerClient { #[tracing::instrument] pub async fn receive_events_on_partition( &self, - partition_id: impl Into + Debug + Clone, + partition_id: String, options: Option, ) -> impl Stream> + '_ { - let partition_id = partition_id.into(); let options = options.unwrap_or_default(); let receiver_name = self @@ -277,12 +274,12 @@ impl ConsumerClient { let mut receiver_options_builder = AmqpReceiverOptions::builder() .with_name(receiver_name.clone()) - .add_property("com.microsoft.com:receiver-name", receiver_name) + .add_property("com.microsoft.com:receiver-name".into(), receiver_name) .with_credit_mode(ReceiverCreditMode::Auto(options.prefetch.unwrap_or(300))) .with_auto_accept(true); if let Some(owner_level) = options.owner_level { - receiver_options_builder = receiver_options_builder.add_property("com.microsoft:epoch", owner_level); + receiver_options_builder = receiver_options_builder.add_property("com.microsoft:epoch".into(), owner_level); } let receiver = AmqpReceiver::new(); @@ -320,7 +317,7 @@ impl ConsumerClient { /// #[tokio::main] /// async fn main() { /// let my_credential = DefaultAzureCredential::new().unwrap(); - /// let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// /// let eventhub_properties = consumer.get_eventhub_properties().await; /// @@ -345,7 +342,7 @@ impl ConsumerClient { .await .get() .ok_or_else(|| azure_core::Error::from(ErrorKind::MissingManagementClient))? - .get_eventhub_properties(&self.eventhub) + .get_eventhub_properties(self.eventhub.clone()) .await } @@ -371,10 +368,10 @@ impl ConsumerClient { /// #[tokio::main] /// async fn main() { /// let my_credential = DefaultAzureCredential::new().unwrap(); - /// let consumer = ConsumerClient::new("my_namespace", "my_eventhub", None, my_credential, None); + /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// let partition_id = "0"; /// - /// let partition_properties = consumer.get_partition_properties(partition_id).await; + /// let partition_properties = consumer.get_partition_properties(partition_id.to_string()).await; /// /// match partition_properties { /// Ok(properties) => { @@ -389,13 +386,10 @@ impl ConsumerClient { /// } /// ``` #[tracing::instrument] - pub async fn get_partition_properties( + pub async fn get_partition_properties( &self, - partition_id: T, - ) -> Result - where - T: Into + Debug, - { + partition_id: String, + ) -> Result { self.ensure_management_client().await?; self.mgmt_client @@ -403,7 +397,7 @@ impl ConsumerClient { .await .get() .ok_or_else(|| azure_core::Error::from(ErrorKind::MissingManagementClient))? - .get_eventhub_partition_properties(&self.eventhub, partition_id) + .get_eventhub_partition_properties(self.eventhub.clone(), partition_id) .await } @@ -436,8 +430,11 @@ impl ConsumerClient { let access_token = self.authorize_path(management_path).await?; trace!("Create management client."); - let management = - AmqpManagement::new(session, "eventhubs_consumer_management", access_token)?; + let management = AmqpManagement::new( + session, + "eventhubs_consumer_management".to_string(), + access_token, + )?; management.attach().await?; mgmt_client .set(ManagementInstance::new(management)) @@ -455,8 +452,7 @@ impl ConsumerClient { self.options .application_id .clone() - .unwrap_or(uuid::Uuid::new_v4().to_string()) - .as_str(), + .unwrap_or(uuid::Uuid::new_v4().to_string()), Url::parse(url).map_err(Error::from)?, Some( AmqpConnectionOptions::builder() @@ -477,8 +473,7 @@ impl ConsumerClient { Ok(()) } - async fn authorize_path(&self, url: impl Into) -> Result { - let url: String = url.into(); + async fn authorize_path(&self, url: String) -> Result { debug!("Authorizing path: {:?}", url); let mut scopes = self.authorization_scopes.lock().await; if self.connection.get().is_none() { @@ -504,8 +499,13 @@ impl ConsumerClient { .await?; debug!("Got token: {:?}", token.token.secret()); let expires_at = token.expires_on; - cbs.authorize_path(&url, token.token.secret(), expires_at) - .await?; + cbs.authorize_path( + url.clone(), + None, + token.token.secret().to_string(), + expires_at, + ) + .await?; // insert returns some if it *fails* to insert, None if it succeeded. let present = scopes.insert(url.clone(), token); @@ -546,40 +546,42 @@ impl ConsumerClient { /// Represents the options for configuring a ConsumerClient. #[derive(Debug, Default)] pub struct ConsumerClientOptions { - application_id: Option, - instance_id: Option, - retry_options: Option, + /// The application ID to set. + pub application_id: Option, + /// The instance ID to set. + pub instance_id: Option, + /// The retry options to set. + pub retry_options: Option, } -impl ConsumerClientOptions { - /// Creates a new `ConsumerClientOptionsBuilder` to configure the consumer client options. - pub fn builder() -> builders::ConsumerClientOptionsBuilder { - builders::ConsumerClientOptionsBuilder::new() - } -} +impl ConsumerClientOptions {} /// Represents the options for receiving events from an Event Hub. #[derive(Debug, Clone, Default)] pub struct ReceiveOptions { - owner_level: Option, - prefetch: Option, - start_position: Option, + /// The owner level for messages being retrieved. + pub owner_level: Option, + /// The prefetch count for messages being retrieved. + pub prefetch: Option, + /// The starting position for messages being retrieved. + pub start_position: Option, } /// Represents the options for receiving events from an Event Hub. -impl ReceiveOptions { - /// Creates a new `ReceiveOptionsBuilder` to configure the receive options. - pub fn builder() -> builders::ReceiveOptionsBuilder { - builders::ReceiveOptionsBuilder::new() - } -} +impl ReceiveOptions {} +/// Represents the starting position of a consumer when receiving events from an Event Hub. #[derive(Debug, Default, PartialEq, Clone)] -pub(crate) enum StartLocation { +pub enum StartLocation { + /// The starting position is specified by an offset. Offset(String), + /// The starting position is specified by a sequence number. SequenceNumber(i64), + /// The starting position is specified by an enqueued time. EnqueuedTime(std::time::SystemTime), + /// The starting position is the earliest event in the partition. Earliest, #[default] + /// The starting position is the latest event in the partition. Latest, } @@ -598,79 +600,66 @@ const SEQUENCE_NUMBER_ANNOTATION: &str = "amqp.annotation.x-opt-sequence-number" /// /// Basic usage: /// -/// ```no_run -/// use azure_messaging_eventhubs::consumer::StartPosition; -/// -/// let start_position = StartPosition::builder() -/// .with_sequence_number(12345) -/// .build(); /// ``` +/// use azure_messaging_eventhubs::consumer::{StartPosition, StartLocation}; /// -/// ```no_run -/// use azure_messaging_eventhubs::consumer::StartPosition; -/// -/// let start_position = StartPosition::builder() -/// .with_sequence_number(12345) -/// .inclusive() -/// .build(); +/// let start_position = StartPosition{ +/// location: StartLocation::SequenceNumber(12345), +/// ..Default::default()};; /// ``` /// -/// ```no_run -/// use azure_messaging_eventhubs::consumer::StartPosition; +/// ``` +/// use azure_messaging_eventhubs::consumer::{StartPosition, StartLocation}; /// -/// let start_position = StartPosition::builder() -/// .with_enqueued_time(std::time::SystemTime::now()) -/// .build(); +/// let start_position = StartPosition{ +/// location: StartLocation::EnqueuedTime(std::time::SystemTime::now()), +/// ..Default::default() +/// }; /// ``` /// -/// ```no_run -/// use azure_messaging_eventhubs::consumer::StartPosition; +/// ``` +/// use azure_messaging_eventhubs::consumer::{StartPosition, StartLocation}; /// -/// let start_position = StartPosition::builder() -/// .with_offset("12345".to_string()) -/// .build(); +/// let start_position = StartPosition{ +/// location: StartLocation::Offset("12345".to_string()), +/// ..Default::default() +/// }; /// ``` /// -/// ```no_run -/// use azure_messaging_eventhubs::consumer::StartPosition; +/// ``` +/// use azure_messaging_eventhubs::consumer::{StartPosition, StartLocation}; /// -/// let start_position = StartPosition::builder() -/// .with_earliest_location() -/// .build(); +/// let start_position = StartPosition{ +/// location: StartLocation::Earliest, +/// ..Default::default() +/// }; /// ``` /// -/// ```no_run -/// use azure_messaging_eventhubs::consumer::StartPosition; +/// ``` +/// use azure_messaging_eventhubs::consumer::{StartPosition, StartLocation}; /// -/// let start_position = StartPosition::builder() -/// .with_latest_location() -/// .build(); +/// let start_position = StartPosition{ +/// location: StartLocation::Latest, +/// ..Default::default() +/// }; /// ``` /// -/// ```no_run +/// ``` /// use azure_messaging_eventhubs::consumer::StartPosition; /// -/// let start_position = StartPosition::builder() -/// .build(); +/// let start_position = StartPosition::default(); /// ``` /// #[derive(Debug, PartialEq, Clone, Default)] pub struct StartPosition { - location: StartLocation, - inclusive: bool, + /// The location of the starting position. + pub location: StartLocation, + + /// Whether the starting position is inclusive (includes the event at StartLocation). + pub inclusive: bool, } impl StartPosition { - /// Creates a new builder to build a `StartPosition`. - /// - /// # Returns - /// - /// A builder which can be used to create a StartPosition. - /// - pub fn builder() -> builders::StartPositionBuilder { - builders::StartPositionBuilder::new() - } - pub(crate) fn start_expression(position: &Option) -> String { if let Some(position) = position { let mut greater_than: &str = ">"; @@ -706,237 +695,6 @@ impl StartPosition { } } -mod builders { - use super::*; - - pub struct ConsumerClientOptionsBuilder { - options: ConsumerClientOptions, - } - - /// Builder for configuring options for the `ConsumerClient`. - impl ConsumerClientOptionsBuilder { - /// Creates a new `ConsumerClientOptionsBuilder` with default options. - pub(super) fn new() -> Self { - Self { - options: Default::default(), - } - } - - /// Sets the application ID for the `ConsumerClient`. - /// - /// # Arguments - /// - /// * `application_id` - The application ID to set. - /// - /// # Returns - /// - /// The updated `ConsumerClientOptionsBuilder`. - /// - /// # Note: The application ID identifies the application, it is used for telemetry. - pub fn with_application_id(mut self, application_id: T) -> Self - where - T: Into, - { - self.options.application_id = Some(application_id.into()); - self - } - - /// Sets the retry options for the `ConsumerClient`. - /// - /// # Arguments - /// - /// * `retry_options` - The retry options to set. - /// - /// # Returns - /// - /// The updated `ConsumerClientOptionsBuilder`. - pub fn with_retry_options(mut self, retry_options: RetryOptions) -> Self { - self.options.retry_options = Some(retry_options); - self - } - - /// Sets the instance ID for the `ConsumerClient`. - /// - /// The "instance ID" uniquely identifies the consumer client instance. If not set, a random UUID will be used. - /// - /// # Arguments - /// - /// * `instance_id` - The instance ID to set. - /// - /// # Returns - /// - /// The updated `ConsumerClientOptionsBuilder`. - /// - pub fn with_instance_id(mut self, instance_id: T) -> Self - where - T: Into, - { - self.options.instance_id = Some(instance_id.into()); - self - } - - /// Builds the `ConsumerClientOptions` using the configured options. - /// - /// # Returns - /// - /// The `ConsumerClientOptions` with the configured options. - pub fn build(self) -> ConsumerClientOptions { - self.options - } - } - - pub struct ReceiveOptionsBuilder { - options: ReceiveOptions, - } - - impl ReceiveOptionsBuilder { - pub(super) fn new() -> Self { - Self { - options: Default::default(), - } - } - - pub fn with_owner_level(mut self, owner_level: i64) -> Self { - self.options.owner_level = Some(owner_level); - self - } - - pub fn with_prefetch(mut self, prefetch: u32) -> Self { - self.options.prefetch = Some(prefetch); - self - } - - pub fn with_start_position(mut self, start_position: StartPosition) -> Self { - self.options.start_position = Some(start_position); - self - } - - pub fn build(self) -> ReceiveOptions { - self.options - } - } - - /// A builder for the `StartPosition` struct. - pub struct StartPositionBuilder { - position: StartPosition, - } - - impl StartPositionBuilder { - pub(super) fn new() -> Self { - Self { - position: Default::default(), - } - } - - /// Sets the starting position to the earliest event in the partition. - /// - /// # Returns - /// - /// A reference to the updated builder. - /// - pub fn with_earliest_location(mut self) -> Self { - self.position.location = StartLocation::Earliest; - self - } - - /// Sets the starting position to the latest event in the partition. - /// - /// # Returns - /// - /// A reference to the updated builder. - /// - pub fn with_latest_location(mut self) -> Self { - self.position.location = StartLocation::Latest; - self - } - - /// Sets the starting position to the event with the specified sequence number. - /// - /// # Parameters - /// - /// - `sequence_number`: The sequence number to start receiving events. - /// - /// # Returns - /// - /// A reference to the updated builder. - /// - /// # Remarks: - /// - /// If the "inclusive" method is not called, the starting position will be greater than the specified sequence number. - /// If the "inclusive" method is called, the message at the starting sequence number will be included. - /// - pub fn with_sequence_number(mut self, sequence_number: i64) -> Self { - self.position.location = StartLocation::SequenceNumber(sequence_number); - self - } - - /// Sets the starting position to the event enqueued at the specified time. - /// - /// # Parameters - /// - /// - `enqueued_time`: The time when the event was enqueued. - /// - /// # Returns - /// - /// A reference to the updated builder. - /// - /// # Remarks - /// - /// If the "inclusive" method is not called, the starting position will be greater than the specified enqueued time. - /// If the "inclusive" method is called, the message enqueued at the specified time will be included. - /// - pub fn with_enqueued_time(mut self, enqueued_time: std::time::SystemTime) -> Self { - self.position.location = StartLocation::EnqueuedTime(enqueued_time); - self - } - - /// Sets the starting position to the event with the specified offset. - /// - /// # Parameters - /// - /// - `offset`: The offset of the event. - /// - /// # Returns - /// - /// A reference to the updated builder. - /// - /// # Remarks - /// - /// If the "inclusive" method is not called, the starting position will be greater than the specified offset. - /// If the "inclusive" method is called, the message at the specified offset will be included. - /// - pub fn with_offset(mut self, offset: String) -> Self { - self.position.location = StartLocation::Offset(offset); - self - } - - /// Sets the starting position to be inclusive. - /// - /// # Returns - /// - /// A reference to the updated builder. - /// - /// # Remarks - /// - /// If this method is called, the message at the starting position will be included. - /// - pub fn inclusive(mut self) -> Self { - self.position.inclusive = true; - self - } - - /// Builds the `StartPosition`. - /// - /// # Returns - /// - /// The built `StartPosition`. - /// - pub fn build(self) -> StartPosition { - self.position - } - } -} - #[cfg(test)] mod tests { use super::*; @@ -963,7 +721,7 @@ mod tests { } { - let options = ConsumerClientOptions::builder().build(); + let options = ConsumerClientOptions::default(); assert!(options.application_id.is_none()); assert!(options.instance_id.is_none()); assert!(options.retry_options.is_none()); @@ -972,11 +730,11 @@ mod tests { #[test] fn test_consumer_client_with_options() { - let options = ConsumerClientOptions::builder() - .with_application_id("test_app_id") - .with_retry_options(RetryOptions::default()) - .with_instance_id("test_instance_id") - .build(); + let options = ConsumerClientOptions { + application_id: Some("test_app_id".to_string()), + instance_id: Some("test_instance_id".to_string()), + retry_options: Some(RetryOptions::default()), + }; assert_eq!(options.application_id, Some("test_app_id".to_string())); assert_eq!(options.instance_id, Some("test_instance_id".to_string())); @@ -986,9 +744,10 @@ mod tests { fn test_start_position_builder_with_sequence_number() { setup(); let sequence_number = 12345i64; - let start_position = StartPosition::builder() - .with_sequence_number(sequence_number) - .build(); + let start_position = StartPosition { + location: StartLocation::SequenceNumber(sequence_number), + ..Default::default() + }; assert_eq!( start_position.location, StartLocation::SequenceNumber(sequence_number) @@ -998,10 +757,11 @@ mod tests { "amqp.annotation.x-opt-sequence-number >'12345'" ); - let start_position = StartPosition::builder() - .with_sequence_number(sequence_number) - .inclusive() - .build(); + let start_position = StartPosition { + location: StartLocation::SequenceNumber(sequence_number), + inclusive: true, + ..Default::default() + }; assert_eq!( StartPosition::start_expression(&Some(start_position)), "amqp.annotation.x-opt-sequence-number >='12345'" @@ -1012,9 +772,10 @@ mod tests { fn test_start_position_builder_with_enqueued_time() { setup(); let enqueued_time = std::time::SystemTime::now(); - let start_position = StartPosition::builder() - .with_enqueued_time(enqueued_time) - .build(); + let start_position = StartPosition { + location: StartLocation::EnqueuedTime(enqueued_time), + ..Default::default() + }; info!("enqueued_time: {:?}", enqueued_time); info!( "enqueued_time: {:?}", @@ -1031,6 +792,7 @@ mod tests { start_position.location, StartLocation::EnqueuedTime(enqueued_time) ); + assert_eq!(start_position.inclusive, false); assert_eq!( StartPosition::start_expression(&Some(start_position)), format!( @@ -1042,10 +804,11 @@ mod tests { ) ); - let start_position = StartPosition::builder() - .with_enqueued_time(enqueued_time) - .inclusive() - .build(); + let start_position = StartPosition { + location: StartLocation::EnqueuedTime(enqueued_time), + inclusive: true, + ..Default::default() + }; assert_eq!( StartPosition::start_expression(&Some(start_position)), format!( @@ -1062,7 +825,10 @@ mod tests { fn test_start_position_builder_with_offset() { setup(); let offset = "12345".to_string(); - let start_position = StartPosition::builder().with_offset(offset.clone()).build(); + let start_position = StartPosition { + location: StartLocation::Offset(offset.clone()), + ..Default::default() + }; assert_eq!( start_position.location, StartLocation::Offset(offset.clone()) @@ -1072,10 +838,11 @@ mod tests { StartPosition::start_expression(&Some(start_position)), ); - let start_position = StartPosition::builder() - .with_offset(offset.clone()) - .inclusive() - .build(); + let start_position = StartPosition { + location: StartLocation::Offset(offset.clone()), + inclusive: true, + ..Default::default() + }; assert_eq!( "amqp.annotation.x-opt-offset >='12345'", StartPosition::start_expression(&Some(start_position)), @@ -1085,9 +852,12 @@ mod tests { #[test] fn test_start_position_builder_inclusive() { setup(); - let start_position = StartPosition::builder().inclusive().build(); + let start_position = StartPosition { + inclusive: true, + ..Default::default() + }; assert!(start_position.inclusive); - let start_position = StartPosition::builder().build(); + let start_position = StartPosition::default(); assert!(!start_position.inclusive); } } diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs index fd38fa7cc1..db7df4bedb 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs @@ -6,6 +6,8 @@ // cspell: words amqp eventdata #![doc = include_str!("../README.md")] +/// let consumer_client = ConsumerClient::new("fully_qualified_domain", "eventhub_name", None, my_credentials, None); +/// let partition_properties = consumer_client.get_partition_properties("0").await?; pub(crate) mod common; /// Types related to consuming events from an Event Hub. @@ -60,7 +62,7 @@ pub mod models { /// # #[tokio::main] /// # async fn main() -> Result<(), Box> { /// # let my_credentials = DefaultAzureCredential::new()?; - /// let consumer_client = azure_messaging_eventhubs::consumer::ConsumerClient::new("fully_qualified_domain", "eventhub_name", None, my_credentials, None); + /// let consumer_client = azure_messaging_eventhubs::consumer::ConsumerClient::new("fully_qualified_domain".to_string(), "eventhub_name".to_string(), None, my_credentials, None); /// /// let eventhub_properties = consumer_client.get_eventhub_properties().await?; /// @@ -76,7 +78,7 @@ pub mod models { pub name: String, /// The time when the Event Hub was created. - pub created_on: std::time::SystemTime, + pub created_on: Option, /// The unique identifiers of the partitions in the Event Hub. pub partition_ids: Vec, @@ -105,9 +107,9 @@ pub mod models { /// # #[tokio::main] /// # async fn main() -> Result<(), Box> { /// # let my_credentials = DefaultAzureCredential::new()?; - /// let consumer_client = azure_messaging_eventhubs::consumer::ConsumerClient::new("fully_qualified_domain", "eventhub_name", None, my_credentials, None); + /// let consumer_client = azure_messaging_eventhubs::consumer::ConsumerClient::new("fully_qualified_domain".to_string(), "eventhub_name".to_string(), None, my_credentials, None); /// - /// let partition_properties = consumer_client.get_partition_properties("0").await?; + /// let partition_properties = consumer_client.get_partition_properties("0".to_string()).await?; /// # Ok(()) } /// ``` /// @@ -129,7 +131,8 @@ pub mod models { pub last_enqueued_offset: String, /// The UTC time when the last event was enqueued in this partition. - pub last_enqueued_time_utc: std::time::SystemTime, + /// This will be `None` if the partition is empty. + pub last_enqueued_time_utc: Option, /// Indicates whether the partition is empty. pub is_empty: bool, @@ -257,10 +260,10 @@ pub mod models { /// /// let event_data = EventData::builder() /// .with_body(b"Hello, world!") - /// .with_content_type("text/plain") + /// .with_content_type("text/plain".to_string()) /// .with_correlation_id("correlation_id") /// .with_message_id("message_id") - /// .add_property("key", "value") + /// .add_property("key".to_string(), "value") /// .build(); /// /// println!("{:?}", event_data); @@ -389,7 +392,7 @@ pub mod models { pub struct ReceivedEventData { message: AmqpMessage, event_data: EventData, - enqueued_time: std::time::SystemTime, + enqueued_time: Option, offset: String, sequence_number: i64, partition_key: String, @@ -422,7 +425,7 @@ pub mod models { } /// The time when the event was sent to the the Event Hub. - pub fn enqueued_time(&self) -> std::time::SystemTime { + pub fn enqueued_time(&self) -> Option { self.enqueued_time } @@ -486,7 +489,8 @@ pub mod models { let event_data = event_data_builder.build(); // Extract the Eventhubs specific properties from the message. - let mut enqueued_time: std::time::SystemTime = std::time::SystemTime::now(); + let mut enqueued_time: Option = + Some(std::time::SystemTime::now()); let mut sequence_number: i64 = 0; let mut partition_key: String = String::new(); let mut offset: String = String::new(); @@ -532,7 +536,7 @@ pub mod models { } } - /// Represents builders for types in the EventHubs Model module. + /// Contains builders for types in the EventHubs Model module. pub mod builders { use super::*; @@ -577,8 +581,8 @@ pub mod models { /// /// A reference to the updated builder. /// - pub fn with_content_type(mut self, content_type: impl Into) -> Self { - self.event_data.content_type = Some(content_type.into()); + pub fn with_content_type(mut self, content_type: String) -> Self { + self.event_data.content_type = Some(content_type); self } @@ -623,17 +627,13 @@ pub mod models { /// /// A reference to the updated builder. /// - pub fn add_property( - mut self, - key: impl Into, - value: impl Into, - ) -> Self { + pub fn add_property(mut self, key: String, value: impl Into) -> Self { if let Some(mut properties) = self.event_data.properties { - properties.insert(key.into(), value.into()); + properties.insert(key, value.into()); self.event_data.properties = Some(properties); } else { let mut properties = HashMap::new(); - properties.insert(key.into(), value.into()); + properties.insert(key, value.into()); self.event_data.properties = Some(properties); } self @@ -737,7 +737,9 @@ mod tests { #[test] fn test_event_data_builder_with_content_type() { let content_type = "application/json"; - let event_data = EventData::builder().with_content_type(content_type).build(); + let event_data = EventData::builder() + .with_content_type(content_type.to_string()) + .build(); assert_eq!(event_data.content_type(), Some(content_type)); } @@ -784,7 +786,7 @@ mod tests { let event_data = EventData::builder() .with_body(body.clone()) - .with_content_type(content_type) + .with_content_type(content_type.to_string()) .with_correlation_id(correlation_id.clone()) .with_message_id(message_id.clone()) .add_property(key.clone(), value.clone()) diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs index f492ade3a9..b62a878f5b 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs @@ -39,7 +39,7 @@ struct EventDataBatchState { /// /// # async fn send_event_batch() -> Result<(), Box> { /// # let credentials = azure_identity::DefaultAzureCredential::new()?; -/// # let producer_client = ProducerClient::new("fully_qualified_domain_name", "event_hub_name", credentials, ProducerClientOptions::builder().build()); +/// # let producer_client = ProducerClient::new("fully_qualified_domain_name".to_string(), "event_hub_name".to_string(), credentials, None); /// /// let mut batch = producer_client.create_batch(None).await?; /// @@ -166,7 +166,7 @@ impl<'a> EventDataBatch<'a> { /// /// # async fn send_event_batch() -> Result<(), Box> { /// # let my_credential = azure_identity::DefaultAzureCredential::new()?; - /// # let producer_client = ProducerClient::new("fully_qualified_domain_name", "event_hub_name", my_credential, ProducerClientOptions::builder().build()); + /// # let producer_client = ProducerClient::new("fully_qualified_domain_name".to_string(), "event_hub_name".to_string(), my_credential, None); /// let mut batch = producer_client.create_batch(None).await?; /// /// let event_data = EventData::builder().build(); @@ -213,7 +213,7 @@ impl<'a> EventDataBatch<'a> { /// /// # async fn send_event_batch() -> Result<(), Box> { /// # let my_credential = azure_identity::DefaultAzureCredential::new()?; - /// # let producer_client = ProducerClient::new("fully_qualified_domain_name", "event_hub_name", my_credential, ProducerClientOptions::builder().build()); + /// # let producer_client = ProducerClient::new("fully_qualified_domain_name".to_string(), "event_hub_name".to_string(), my_credential, None); /// let mut batch = producer_client.create_batch(None).await?; /// /// let amqp_message = AmqpMessage::builder().build(); @@ -339,74 +339,23 @@ impl<'a> EventDataBatch<'a> { /// ``` /// use azure_messaging_eventhubs::producer::batch::EventDataBatchOptions; /// -/// let options = EventDataBatchOptions::builder() -/// .with_max_size_in_bytes(1024) -/// .with_partition_key("pk") -/// .with_partition_id("pid") -/// .build(); +/// let options = EventDataBatchOptions{ +/// max_size_in_bytes: Some(1024), +/// partition_key: Some("pk".to_string()), +/// partition_id: Some("12".to_string()), +/// ..Default::default()}; /// ``` /// #[derive(Default)] pub struct EventDataBatchOptions { - max_size_in_bytes: Option, - partition_key: Option, - partition_id: Option, -} - -impl EventDataBatchOptions { - /// Creates a new `EventDataBatchOptionsBuilder` to build an `EventDataBatchOptions`. - /// - /// # Returns - /// - /// An `EventDataBatchOptionsBuilder`. - /// - pub fn builder() -> builders::EventDataBatchOptionsBuilder { - builders::EventDataBatchOptionsBuilder::new() - } -} + /// The maximum size of the batch in bytes. + pub max_size_in_bytes: Option, -mod builders { - use super::*; + /// The partition key to use when writing messages. + pub partition_key: Option, - pub struct EventDataBatchOptionsBuilder { - options: EventDataBatchOptions, - } - - impl EventDataBatchOptionsBuilder { - pub(super) fn new() -> Self { - Self { - options: Default::default(), - } - } - - /// Sets the maximum size of the batch in bytes. - pub fn with_max_size_in_bytes(mut self, max_size_in_bytes: u64) -> Self { - self.options.max_size_in_bytes = Some(max_size_in_bytes); - self - } - - /// Sets the target partition key for the batch. - pub fn with_partition_key(mut self, partition_key: impl Into) -> Self { - self.options.partition_key = Some(partition_key.into()); - self - } - - /// Sets the target partition ID for the batch. - pub fn with_partition_id(mut self, partition_id: impl Into) -> Self { - self.options.partition_id = Some(partition_id.into()); - self - } - - /// Builds the `EventDataBatchOptions`. - /// - /// # Returns - /// - /// An `EventDataBatchOptions`. - /// - pub fn build(self) -> EventDataBatchOptions { - self.options - } - } + /// The partition ID to use as the target partition for the messages being written. + pub partition_id: Option, } #[cfg(test)] @@ -415,28 +364,15 @@ mod tests { #[test] fn test_batch_builder() { - let options = EventDataBatchOptions::builder() - .with_max_size_in_bytes(1024) - .with_partition_key("pk") - .with_partition_id("pid") - .build(); + let options = EventDataBatchOptions { + max_size_in_bytes: Some(1024), + partition_key: Some("pk".to_string()), + partition_id: Some("pid".to_string()), + ..Default::default() + }; assert_eq!(options.max_size_in_bytes, Some(1024)); assert_eq!(options.partition_key, Some("pk".to_string())); assert_eq!(options.partition_id, Some("pid".to_string())); } - - #[test] - fn test_clone_array() { - let mut array = vec![1, 2, 3, 4, 5]; - let mut copy = Vec::::new(); - - // while let Some(val) = array.pop() { - // println!("{:?}", val); - // copy.push(val); - // } - copy.append(&mut array); - assert_eq!(array.len(), 0); - assert_eq!(copy, vec![1, 2, 3, 4, 5]); - } } diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/mod.rs index 17fd7121f1..a5db688148 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/mod.rs @@ -24,6 +24,7 @@ use azure_core::RetryOptions; use azure_core::{ credentials::AccessToken, error::{Error, Result}, + Uuid, }; use batch::{EventDataBatch, EventDataBatchOptions}; use std::collections::HashMap; @@ -37,20 +38,20 @@ pub mod batch; const DEFAULT_EVENTHUBS_APPLICATION: &str = "DefaultApplicationName"; /// Options used when creating an Event Hubs ProducerClient. -#[derive(Default)] +#[derive(Default, Debug, Clone)] pub struct ProducerClientOptions { - application_id: Option, - retry_options: Option, - max_message_size: Option, -} + /// The application id that will be used to identify the client. + pub application_id: Option, -impl ProducerClientOptions { - /// Creates a builder to create ProducerClientOptions. - pub fn builder() -> builders::ProducerClientOptionsBuilder { - builders::ProducerClientOptionsBuilder::new() - } + /// The options used to configure retry operations. + pub retry_options: Option, + + /// The maximum size of a message that can be sent to the Event Hub. + pub max_message_size: Option, } +impl ProducerClientOptions {} + struct SenderInstance { #[allow(dead_code)] session: AmqpSession, @@ -75,10 +76,11 @@ struct SenderInstance { /// let fully_qualified_namespace = std::env::var("EVENT_HUB_NAMESPACE")?; /// let eventhub_name = std::env::var("EVENT_HUB_NAME")?; /// let my_credentials = DefaultAzureCredential::new()?; -/// let options = ProducerClientOptions::builder() -/// .with_application_id("your_application_id") -/// .build(); -/// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, options); +/// let options = ProducerClientOptions{ +/// application_id: Some("your_application_id".to_string()), +/// ..Default::default() +/// }; +/// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, Some(options)); /// producer.open().await?; /// Ok(()) /// } @@ -108,15 +110,13 @@ impl ProducerClient { /// /// A new instance of `ProducerClient`. pub fn new( - fully_qualified_namespace: impl Into, - eventhub: impl Into, + fully_qualified_namespace: String, + eventhub: String, credential: Arc, - options: ProducerClientOptions, + options: Option, ) -> Self { - let eventhub: String = eventhub.into(); - let fully_qualified_namespace: String = fully_qualified_namespace.into(); Self { - options, + options: options.unwrap_or_default(), connection: OnceLock::new(), credential: credential.clone(), url: format!("amqps://{}/{}", fully_qualified_namespace, eventhub), @@ -172,10 +172,11 @@ impl ProducerClient { /// let fully_qualified_namespace = std::env::var("EVENT_HUB_NAMESPACE")?; /// let eventhub_name = std::env::var("EVENT_HUB_NAME")?; /// let my_credentials = DefaultAzureCredential::new()?; - /// let options = ProducerClientOptions::builder() - /// .with_application_id("your_application_id") - /// .build(); - /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, options); + /// let options = ProducerClientOptions{ + /// application_id: Some("your_application_id".to_string()), + /// ..Default::default() + /// }; + /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, Some(options)); /// producer.open().await?; /// let mut batch = producer.create_batch(None).await?; /// Ok(()) @@ -214,10 +215,11 @@ impl ProducerClient { /// let fully_qualified_namespace = std::env::var("EVENT_HUB_NAMESPACE")?; /// let eventhub_name = std::env::var("EVENT_HUB_NAME")?; /// let my_credentials = DefaultAzureCredential::new()?; - /// let options = ProducerClientOptions::builder() - /// .with_application_id("your_application_id") - /// .build(); - /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, options); + /// let options = ProducerClientOptions{ + /// application_id: Some("your_application_id".to_string()), + /// ..Default::default() + /// }; + /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, Some(options)); /// producer.open().await?; /// let mut batch = producer.create_batch(None).await?; /// batch.try_add_event_data("Hello, World!", None)?; @@ -259,7 +261,7 @@ impl ProducerClient { /// let fully_qualified_namespace = std::env::var("EVENT_HUB_NAMESPACE")?; /// let eventhub_name = std::env::var("EVENT_HUB_NAME")?; /// let my_credentials = DefaultAzureCredential::new()?; - /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, ProducerClientOptions::builder().build()); + /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, None); /// producer.open().await?; /// let properties = producer.get_eventhub_properties().await?; /// println!("Event Hub: {:?}", properties); @@ -274,7 +276,7 @@ impl ProducerClient { .await .get() .ok_or_else(|| azure_core::Error::from(ErrorKind::MissingManagementClient))? - .get_eventhub_properties(&self.eventhub) + .get_eventhub_properties(self.eventhub.clone()) .await } @@ -297,16 +299,16 @@ impl ProducerClient { /// let eventhub_name = std::env::var("EVENT_HUB_NAME")?; /// let eventhub_name = std::env::var("EVENT_HUB_NAME")?; /// let my_credentials = DefaultAzureCredential::new()?; - /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, ProducerClientOptions::builder().build()); + /// let producer = ProducerClient::new(fully_qualified_namespace, eventhub_name, my_credentials, None); /// producer.open().await?; - /// let partition_properties = producer.get_partition_properties("0").await?; + /// let partition_properties = producer.get_partition_properties("0".to_string()).await?; /// println!("Event Hub: {:?}", partition_properties); /// Ok(()) /// } /// ``` pub async fn get_partition_properties( &self, - partition_id: impl Into, + partition_id: String, ) -> Result { self.ensure_management_client().await?; @@ -315,7 +317,7 @@ impl ProducerClient { .await .get() .ok_or_else(|| azure_core::Error::from(ErrorKind::MissingManagementClient))? - .get_eventhub_partition_properties(&self.eventhub, partition_id) + .get_eventhub_partition_properties(self.eventhub.clone(), partition_id) .await } @@ -352,7 +354,8 @@ impl ProducerClient { let access_token = self.authorize_path(management_path).await?; trace!("Create management client."); - let management = AmqpManagement::new(session, "eventhubs_management", access_token)?; + let management = + AmqpManagement::new(session, "eventhubs_management".to_string(), access_token)?; management.attach().await?; mgmt_client .set(ManagementInstance::new(management)) @@ -369,8 +372,7 @@ impl ProducerClient { self.options .application_id .clone() - .unwrap_or(uuid::Uuid::new_v4().to_string()) - .as_str(), + .unwrap_or(Uuid::new_v4().to_string()), Url::parse(url).map_err(Error::from)?, Some( AmqpConnectionOptions::builder() @@ -391,8 +393,7 @@ impl ProducerClient { Ok(()) } - async fn ensure_sender(&self, path: impl Into) -> Result>> { - let path: String = path.into(); + async fn ensure_sender(&self, path: String) -> Result>> { let mut sender_instances = self.sender_instances.lock().await; if !sender_instances.contains_key(&path) { self.ensure_connection(&path).await?; @@ -450,8 +451,7 @@ impl ProducerClient { .clone()) } - async fn authorize_path(&self, url: impl Into) -> Result { - let url: String = url.into(); + async fn authorize_path(&self, url: String) -> Result { debug!("Authorizing path: {:?}", url); let mut scopes = self.authorization_scopes.lock().await; if self.connection.get().is_none() { @@ -477,8 +477,13 @@ impl ProducerClient { .await?; debug!("Got token: {:?}", token.token.secret()); let expires_at = token.expires_on; - cbs.authorize_path(&url, token.token.secret(), expires_at) - .await?; + cbs.authorize_path( + url.clone(), + None, + token.token.secret().to_string(), + expires_at, + ) + .await?; let present = scopes.insert(url.clone(), token); // insert returns some if it *fails* to insert, None if it succeeded. if present.is_some() { @@ -492,40 +497,6 @@ impl ProducerClient { } } -mod builders { - use super::*; - pub struct ProducerClientOptionsBuilder { - options: ProducerClientOptions, - } - - impl ProducerClientOptionsBuilder { - pub(super) fn new() -> Self { - Self { - options: Default::default(), - } - } - - pub fn with_application_id(mut self, application_id: impl Into) -> Self { - self.options.application_id = Some(application_id.into()); - self - } - - pub fn with_retry_options(mut self, retry_options: RetryOptions) -> Self { - self.options.retry_options = Some(retry_options); - self - } - - pub fn with_max_message_size(mut self, max_message_size: u64) -> Self { - self.options.max_message_size = Some(max_message_size); - self - } - - pub fn build(self) -> ProducerClientOptions { - self.options - } - } -} - #[cfg(test)] mod tests { @@ -533,10 +504,12 @@ mod tests { #[test] fn test_producer_client_options_builder() { - let options = ProducerClientOptions::builder() - .with_application_id("application_id") - .with_retry_options(RetryOptions::default()) - .build(); + let options = ProducerClientOptions { + application_id: Some("application_id".to_string()), + retry_options: Some(RetryOptions::default()), + ..Default::default() + }; + assert_eq!(options.application_id.unwrap(), "application_id"); } } diff --git a/sdk/eventhubs/azure_messaging_eventhubs/tests/consumer.rs b/sdk/eventhubs/azure_messaging_eventhubs/tests/consumer.rs index 27c5a3c966..0d58d3c3ef 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/tests/consumer.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/tests/consumer.rs @@ -26,11 +26,10 @@ async fn test_new() { eventhub, None, DefaultAzureCredential::new().unwrap(), - Some( - ConsumerClientOptions::builder() - .with_application_id("test_new") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_new".to_string()), + ..Default::default() + }), ); } @@ -40,15 +39,14 @@ async fn test_new_with_error() { trace!("test_new_with_error"); let eventhub = env::var("EVENTHUB_NAME").unwrap(); let consumer = ConsumerClient::new( - "invalid_host", + "invalid_host".into(), eventhub, None, DefaultAzureCredential::new().unwrap(), - Some( - ConsumerClientOptions::builder() - .with_application_id("test_new") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_new".to_string()), + ..Default::default() + }), ); let result = consumer.open().await; assert!(result.is_err()); @@ -65,11 +63,10 @@ async fn test_open() { eventhub, None, azure_identity::DefaultAzureCredential::new().unwrap(), - Some( - ConsumerClientOptions::builder() - .with_application_id("test_open") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_open".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); } @@ -83,11 +80,10 @@ async fn test_close() { eventhub, None, azure_identity::DefaultAzureCredential::new().unwrap(), - Some( - ConsumerClientOptions::builder() - .with_application_id("test_close") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_open".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); client.close().await.unwrap(); @@ -106,11 +102,10 @@ async fn test_get_properties() { eventhub.clone(), None, credential, - Some( - ConsumerClientOptions::builder() - .with_application_id("test_get_properties") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_open".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); let properties = client.get_eventhub_properties().await.unwrap(); @@ -131,11 +126,10 @@ async fn test_get_partition_properties() { eventhub, None, credential, - Some( - ConsumerClientOptions::builder() - .with_application_id("test_get_properties") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_open".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); let properties = client.get_eventhub_properties().await.unwrap(); @@ -167,11 +161,10 @@ async fn receive_lots_of_events() { eventhub, None, credential, - Some( - ConsumerClientOptions::builder() - .with_application_id("receive_lots_of_events") - .build(), - ), + Some(ConsumerClientOptions { + application_id: Some("test_open".to_string()), + ..Default::default() + }), ); info!("Opening client."); @@ -180,12 +173,14 @@ async fn receive_lots_of_events() { info!("Creating event receive stream."); let event_stream = client .receive_events_on_partition( - "0", - Some( - ReceiveOptions::builder() - .with_start_position(StartPosition::builder().with_earliest_location().build()) - .build(), - ), + "0".to_string(), + Some(ReceiveOptions { + start_position: Some(StartPosition { + location: azure_messaging_eventhubs::consumer::StartLocation::Earliest, + ..Default::default() + }), + ..Default::default() + }), ) .await; diff --git a/sdk/eventhubs/azure_messaging_eventhubs/tests/producer.rs b/sdk/eventhubs/azure_messaging_eventhubs/tests/producer.rs index 58347836ca..c38caeac51 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/tests/producer.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/tests/producer.rs @@ -27,9 +27,10 @@ async fn test_new() { host, eventhub, DefaultAzureCredential::new().unwrap(), - ProducerClientOptions::builder() - .with_application_id("test_new") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_new".to_string()), + ..Default::default() + }), ); } @@ -38,12 +39,13 @@ async fn test_new_with_error() { common::setup(); let eventhub = env::var("EVENTHUB_NAME").unwrap(); let producer = ProducerClient::new( - "invalid_host", + "invalid_host".to_string(), eventhub, azure_identity::DefaultAzureCredential::new().unwrap(), - ProducerClientOptions::builder() - .with_application_id("test_new_with_error") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_new_with_error".to_string()), + ..Default::default() + }), ); let result = producer.open().await; assert!(result.is_err()); @@ -59,9 +61,10 @@ async fn test_open() { host, eventhub, azure_identity::DefaultAzureCredential::new().unwrap(), - ProducerClientOptions::builder() - .with_application_id("test_open") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_open".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); } @@ -74,9 +77,10 @@ async fn test_close() { host, eventhub, azure_identity::DefaultAzureCredential::new().unwrap(), - ProducerClientOptions::builder() - .with_application_id("test_close") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_close".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); client.close().await.unwrap(); @@ -94,9 +98,10 @@ async fn test_get_properties() { host, eventhub.clone(), credential, - ProducerClientOptions::builder() - .with_application_id("test_get_properties") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_get_properties".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); let properties = client.get_eventhub_properties().await.unwrap(); @@ -116,9 +121,10 @@ async fn test_get_partition_properties() { host, eventhub.clone(), credential, - ProducerClientOptions::builder() - .with_application_id("test_get_properties") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_get_partition_properties".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); let properties = client.get_eventhub_properties().await.unwrap(); @@ -150,10 +156,10 @@ fn test_create_eventdata() { let data = b"hello world"; let _ = azure_messaging_eventhubs::models::EventData::builder() .with_body(data.to_vec()) - .with_content_type("text/plain") + .with_content_type("text/plain".to_string()) .with_correlation_id("correlation_id") .with_message_id(35u64) - .add_property("key", "value") + .add_property("key".to_string(), "value") .build(); } @@ -169,9 +175,10 @@ async fn test_create_batch() { host, eventhub.clone(), credential, - ProducerClientOptions::builder() - .with_application_id("test_create_batch") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_create_batch".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); { @@ -192,9 +199,10 @@ async fn test_create_and_send_batch() { host, eventhub.clone(), credential, - ProducerClientOptions::builder() - .with_application_id("test_create_batch") - .build(), + Some(ProducerClientOptions { + application_id: Some("test_create_and_send_batch".to_string()), + ..Default::default() + }), ); client.open().await.unwrap(); { @@ -207,11 +215,10 @@ async fn test_create_and_send_batch() { } { let mut batch = client - .create_batch(Some( - EventDataBatchOptions::builder() - .with_partition_id("0") - .build(), - )) + .create_batch(Some(EventDataBatchOptions { + partition_id: Some("0".to_string()), + ..Default::default() + })) .await .unwrap(); for i in 0..10 { @@ -244,9 +251,10 @@ async fn test_add_amqp_messages_to_batch() -> Result<(), Box Result<(), Box Result<(), Box Date: Tue, 5 Nov 2024 14:28:57 -0800 Subject: [PATCH 02/11] Removed impl Into --- sdk/core/azure_core_amqp/src/connection.rs | 4 +-- .../azure_core_amqp/src/fe2o3/connection.rs | 4 +-- .../src/fe2o3/messaging/message_fields.rs | 8 +++--- sdk/core/azure_core_amqp/src/messaging.rs | 26 +++++++------------ sdk/core/azure_core_amqp/src/noop.rs | 2 +- .../src/consumer/mod.rs | 2 +- .../azure_messaging_eventhubs/src/lib.rs | 2 +- .../src/producer/batch.rs | 6 ++++- 8 files changed, 25 insertions(+), 29 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/connection.rs b/sdk/core/azure_core_amqp/src/connection.rs index 12f2e75c7d..a451853cda 100644 --- a/sdk/core/azure_core_amqp/src/connection.rs +++ b/sdk/core/azure_core_amqp/src/connection.rs @@ -69,7 +69,7 @@ pub trait AmqpConnectionApis { fn close(&self) -> impl std::future::Future>; fn close_with_error( &self, - condition: impl Into, + condition: AmqpSymbol, description: Option, info: Option>, ) -> impl std::future::Future>; @@ -94,7 +94,7 @@ impl AmqpConnectionApis for AmqpConnection { } fn close_with_error( &self, - condition: impl Into, + condition: AmqpSymbol, description: Option, info: Option>, ) -> impl std::future::Future> { diff --git a/sdk/core/azure_core_amqp/src/fe2o3/connection.rs b/sdk/core/azure_core_amqp/src/fe2o3/connection.rs index 071e276573..5b54bcee84 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/connection.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/connection.rs @@ -133,7 +133,7 @@ impl AmqpConnectionApis for Fe2o3AmqpConnection { } async fn close_with_error( &self, - condition: impl Into, + condition: AmqpSymbol, description: Option, info: Option>, ) -> Result<()> { @@ -152,7 +152,7 @@ impl AmqpConnectionApis for Fe2o3AmqpConnection { .borrow_mut() .close_with_error(fe2o3_amqp::types::definitions::Error::new( fe2o3_amqp::types::definitions::ErrorCondition::Custom( - fe2o3_amqp_types::primitives::Symbol::from(condition.into()), + fe2o3_amqp_types::primitives::Symbol::from(condition), ), description, info.map(|i| i.into()), diff --git a/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs b/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs index bbd9f9d43a..7b0c8d0d64 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/messaging/message_fields.rs @@ -363,11 +363,11 @@ impl From for AmqpMessageProperties { } if let Some(content_type) = properties.content_type { amqp_message_properties_builder = - amqp_message_properties_builder.with_content_type(content_type); + amqp_message_properties_builder.with_content_type(content_type.into()); } if let Some(content_encoding) = properties.content_encoding { amqp_message_properties_builder = - amqp_message_properties_builder.with_content_encoding(content_encoding); + amqp_message_properties_builder.with_content_encoding(content_encoding.into()); } if let Some(absolute_expiry_time) = properties.absolute_expiry_time { amqp_message_properties_builder = @@ -480,8 +480,8 @@ fn test_properties_conversion() { let properties = AmqpMessageProperties::builder() .with_absolute_expiry_time(time_now) - .with_content_encoding("content_encoding") - .with_content_type("content_type") + .with_content_encoding(crate::value::AmqpSymbol("content_encoding".to_string())) + .with_content_type(crate::value::AmqpSymbol("content_type".to_string())) .with_correlation_id("correlation_id") .with_creation_time(time_now) .with_group_id("group_id".to_string()) diff --git a/sdk/core/azure_core_amqp/src/messaging.rs b/sdk/core/azure_core_amqp/src/messaging.rs index 15bb69c693..f93032e04a 100644 --- a/sdk/core/azure_core_amqp/src/messaging.rs +++ b/sdk/core/azure_core_amqp/src/messaging.rs @@ -1152,17 +1152,13 @@ impl AmqpMessage { /// message.add_message_annotation("key", "value"); /// ``` /// - pub fn add_message_annotation( - &mut self, - name: impl Into, - value: impl Into, - ) { + pub fn add_message_annotation(&mut self, name: AmqpSymbol, value: impl Into) { if let Some(annotations) = self.message_annotations.as_mut() { - annotations.insert(name.into(), value.into()); + annotations.insert(name, value.into()); self.message_annotations = Some(annotations.clone()); } else { let mut annotations = AmqpAnnotations::new(); - annotations.insert(name.into(), value.into()); + annotations.insert(name, value.into()); self.message_annotations = Some(annotations); } } @@ -1320,16 +1316,12 @@ pub mod builders { self.source.filter = Some(filter.into()); self } - pub fn add_to_filter( - mut self, - key: impl Into, - value: impl Into, - ) -> Self { + pub fn add_to_filter(mut self, key: AmqpSymbol, value: impl Into) -> Self { if let Some(filter) = &mut self.source.filter { - filter.insert(key.into(), value.into()); + filter.insert(key, value.into()); } else { let mut filter = AmqpOrderedMap::new(); - filter.insert(key.into(), value.into()); + filter.insert(key, value.into()); self.source.filter = Some(filter); } self @@ -1469,11 +1461,11 @@ pub mod builders { self.properties.correlation_id = Some(correlation_id.into()); self } - pub fn with_content_type(mut self, content_type: impl Into) -> Self { + pub fn with_content_type(mut self, content_type: AmqpSymbol) -> Self { self.properties.content_type = Some(content_type.into()); self } - pub fn with_content_encoding(mut self, content_encoding: impl Into) -> Self { + pub fn with_content_encoding(mut self, content_encoding: AmqpSymbol) -> Self { self.properties.content_encoding = Some(content_encoding.into()); self } @@ -1657,7 +1649,7 @@ mod tests { .with_subject("subject".to_string()) .with_reply_to("reply_to".to_string()) .with_correlation_id(test_uuid2) - .with_content_type("content_type") + .with_content_type(AmqpSymbol::from("content_type")) .with_content_encoding(AmqpSymbol::from("content_encoding")) .with_absolute_expiry_time(time_now) .with_creation_time(time_now) diff --git a/sdk/core/azure_core_amqp/src/noop.rs b/sdk/core/azure_core_amqp/src/noop.rs index 2d4da8670b..ef1dd1899f 100644 --- a/sdk/core/azure_core_amqp/src/noop.rs +++ b/sdk/core/azure_core_amqp/src/noop.rs @@ -56,7 +56,7 @@ impl AmqpConnectionApis for NoopAmqpConnection { async fn close_with_error( &self, - condition: impl Into, + condition: AmqpSymbol, description: Option, info: Option>, ) -> Result<()> { diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs index ba5b3d639e..d6d11c2cac 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs @@ -264,7 +264,7 @@ impl ConsumerClient { let message_source = AmqpSource::builder() .with_address(source_url) .add_to_filter( - AmqpSourceFilter::selector_filter().description(), + AmqpSourceFilter::selector_filter().description().into(), Box::new(AmqpDescribed::new( AmqpSourceFilter::selector_filter().code(), start_expression, diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs index db7df4bedb..4d94d0978a 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/lib.rs @@ -359,7 +359,7 @@ pub mod models { let mut message_properties_builder = AmqpMessageProperties::builder(); if let Some(content_type) = event_data.content_type { message_properties_builder = - message_properties_builder.with_content_type(content_type); + message_properties_builder.with_content_type(content_type.into()); } if let Some(correlation_id) = event_data.correlation_id { message_properties_builder = diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs index b62a878f5b..dd395352ab 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs @@ -12,6 +12,7 @@ use azure_core::{error::Result, Error}; use azure_core_amqp::{ messaging::{AmqpMessage, AmqpMessageBody}, sender::AmqpSenderApis, + value::AmqpSymbol, }; use tracing::debug; use uuid::Uuid; @@ -233,7 +234,10 @@ impl<'a> EventDataBatch<'a> { message.set_message_id(Uuid::new_v4()); } if let Some(partition_key) = self.partition_key.as_ref() { - message.add_message_annotation("x-opt-partition-key", partition_key.clone()); + message.add_message_annotation( + AmqpSymbol::from("x-opt-partition-key"), + partition_key.clone(), + ); } let mut batch_state = self.batch_state.lock().unwrap(); From bb2bb2ae26b624b19956c2fba65c2e01f76a6fbb Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Tue, 5 Nov 2024 14:36:55 -0800 Subject: [PATCH 03/11] doctest fix --- sdk/core/azure_core_amqp/src/messaging.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/core/azure_core_amqp/src/messaging.rs b/sdk/core/azure_core_amqp/src/messaging.rs index f93032e04a..b22cf2e20d 100644 --- a/sdk/core/azure_core_amqp/src/messaging.rs +++ b/sdk/core/azure_core_amqp/src/messaging.rs @@ -1148,8 +1148,9 @@ impl AmqpMessage { /// # Examples /// ``` /// use azure_core_amqp::messaging::AmqpMessage; + /// use azure_core_amqp::value::AmqpSymbol; /// let mut message = AmqpMessage::default(); - /// message.add_message_annotation("key", "value"); + /// message.add_message_annotation(AmqpSymbol::from("key"), "value"); /// ``` /// pub fn add_message_annotation(&mut self, name: AmqpSymbol, value: impl Into) { From 9dad0328777178e034a51efe6a2dee93b8fe4caf Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Tue, 5 Nov 2024 14:40:02 -0800 Subject: [PATCH 04/11] clippy --- sdk/core/azure_core_amqp/src/messaging.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/messaging.rs b/sdk/core/azure_core_amqp/src/messaging.rs index b22cf2e20d..84c68bf568 100644 --- a/sdk/core/azure_core_amqp/src/messaging.rs +++ b/sdk/core/azure_core_amqp/src/messaging.rs @@ -1463,11 +1463,11 @@ pub mod builders { self } pub fn with_content_type(mut self, content_type: AmqpSymbol) -> Self { - self.properties.content_type = Some(content_type.into()); + self.properties.content_type = Some(content_type); self } pub fn with_content_encoding(mut self, content_encoding: AmqpSymbol) -> Self { - self.properties.content_encoding = Some(content_encoding.into()); + self.properties.content_encoding = Some(content_encoding); self } pub fn with_absolute_expiry_time( From 6b17fa6582e4108aff00397b01345037b2093777 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Tue, 5 Nov 2024 14:51:34 -0800 Subject: [PATCH 05/11] Cleaned up comment --- sdk/core/azure_core_amqp/src/cbs.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/cbs.rs b/sdk/core/azure_core_amqp/src/cbs.rs index f4276faae9..d8e9f2d4eb 100644 --- a/sdk/core/azure_core_amqp/src/cbs.rs +++ b/sdk/core/azure_core_amqp/src/cbs.rs @@ -37,10 +37,10 @@ pub trait AmqpClaimsBasedSecurityApis { /// /// # Parameters /// - /// - `path`: A `String` reference representing the AMQP path to be authorized. - /// - `token_type`: An optional `String` representing the type of token used for authorization. This is either "servicebus.windows.net:sastoken" or "jwt". If it is not supplied, "jwt" is assumed. - /// - `secret`: An implementor of `Into` representing the secret used for authorization. This is typically a JSON Web token. - /// - `expires_on`: A `time::OffsetDateTime` representing the expiration time of the authorization. + /// - `path`: A string representing the AMQP path to be authorized. + /// - `token_type`: An optional string representing the type of token used for authorization. This is either "servicebus.windows.net:sastoken" or "jwt". If it is not supplied, "jwt" is assumed. + /// - `secret`: A string representing the secret used for authorization. This is typically a JSON Web token. + /// - `expires_on`: The expiration time of the authorization. /// /// # Returns /// From 565b409cea0ffcf0214d563e53cf00cb019477a0 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Wed, 6 Nov 2024 12:17:28 -0800 Subject: [PATCH 06/11] PR feedback - removed Debug from service clients; removed tracing::instrument, contains_key takes a borrowed key, not an owned key --- sdk/core/azure_core_amqp/src/cbs.rs | 2 -- sdk/core/azure_core_amqp/src/connection.rs | 2 +- sdk/core/azure_core_amqp/src/fe2o3/cbs.rs | 8 ++------ sdk/core/azure_core_amqp/src/fe2o3/receiver.rs | 3 +-- sdk/core/azure_core_amqp/src/fe2o3/sender.rs | 3 +-- sdk/core/azure_core_amqp/src/management.rs | 2 -- sdk/core/azure_core_amqp/src/noop.rs | 12 ++++++------ sdk/core/azure_core_amqp/src/receiver.rs | 4 ++-- sdk/core/azure_core_amqp/src/sender.rs | 4 ++-- sdk/core/azure_core_amqp/src/session.rs | 4 ++-- sdk/core/azure_core_amqp/src/value.rs | 14 ++++++++++---- sdk/eventhubs/azure_messaging_eventhubs/README.md | 6 ++++-- .../azure_messaging_eventhubs/src/common/mod.rs | 7 +++---- .../azure_messaging_eventhubs/src/consumer/mod.rs | 11 +---------- 14 files changed, 35 insertions(+), 47 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/cbs.rs b/sdk/core/azure_core_amqp/src/cbs.rs index d8e9f2d4eb..6167f24851 100644 --- a/sdk/core/azure_core_amqp/src/cbs.rs +++ b/sdk/core/azure_core_amqp/src/cbs.rs @@ -3,7 +3,6 @@ // cspell: words amqp sasl sastoken use azure_core::error::Result; -use std::fmt::Debug; use super::session::AmqpSession; @@ -57,7 +56,6 @@ pub trait AmqpClaimsBasedSecurityApis { ) -> impl std::future::Future>; } -#[derive(Debug)] pub struct AmqpClaimsBasedSecurity<'a> { implementation: CbsImplementation<'a>, } diff --git a/sdk/core/azure_core_amqp/src/connection.rs b/sdk/core/azure_core_amqp/src/connection.rs index a451853cda..ac2a91bc24 100644 --- a/sdk/core/azure_core_amqp/src/connection.rs +++ b/sdk/core/azure_core_amqp/src/connection.rs @@ -75,7 +75,7 @@ pub trait AmqpConnectionApis { ) -> impl std::future::Future>; } -#[derive(Debug, Default)] +#[derive(Default)] pub struct AmqpConnection { pub(crate) implementation: ConnectionImplementation, } diff --git a/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs b/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs index 3519d7b082..4cb6ec8db2 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/cbs.rs @@ -9,10 +9,9 @@ use azure_core::error::Result; use fe2o3_amqp_cbs::token::CbsToken; use fe2o3_amqp_types::primitives::Timestamp; use std::borrow::BorrowMut; -use std::{fmt::Debug, sync::OnceLock}; +use std::sync::OnceLock; use tracing::{debug, trace}; -#[derive(Debug)] pub(crate) struct Fe2o3ClaimsBasedSecurity<'a> { cbs: OnceLock>, session: &'a AmqpSession, @@ -79,10 +78,7 @@ impl AmqpClaimsBasedSecurityApis for Fe2o3ClaimsBasedSecurity<'_> { ); let cbs_token = CbsToken::new( secret, - match token_type { - Some(token_type) => token_type, - None => "jwt".to_string(), - }, + token_type.unwrap_or("jwt".to_string()), Some(Timestamp::from( expires_at .to_offset(time::UtcOffset::UTC) diff --git a/sdk/core/azure_core_amqp/src/fe2o3/receiver.rs b/sdk/core/azure_core_amqp/src/fe2o3/receiver.rs index 07a8f3a763..d510434525 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/receiver.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/receiver.rs @@ -12,7 +12,7 @@ use std::borrow::BorrowMut; use std::sync::{Arc, OnceLock}; use tracing::trace; -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct Fe2o3AmqpReceiver { receiver: OnceLock>>, } @@ -84,7 +84,6 @@ impl AmqpReceiverApis for Fe2o3AmqpReceiver { .max_message_size()) } - #[tracing::instrument] async fn receive(&self) -> Result { let mut receiver = self .receiver diff --git a/sdk/core/azure_core_amqp/src/fe2o3/sender.rs b/sdk/core/azure_core_amqp/src/fe2o3/sender.rs index b4d5352866..80e5bd7a74 100644 --- a/sdk/core/azure_core_amqp/src/fe2o3/sender.rs +++ b/sdk/core/azure_core_amqp/src/fe2o3/sender.rs @@ -15,7 +15,7 @@ use super::error::{ Fe2o3AmqpError, }; -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct Fe2o3AmqpSender { sender: OnceLock>, } @@ -106,7 +106,6 @@ impl AmqpSenderApis for Fe2o3AmqpSender { .max_message_size()) } - #[tracing::instrument] async fn send( &self, message: impl Into + std::fmt::Debug, diff --git a/sdk/core/azure_core_amqp/src/management.rs b/sdk/core/azure_core_amqp/src/management.rs index a1b52c1074..12886996c0 100644 --- a/sdk/core/azure_core_amqp/src/management.rs +++ b/sdk/core/azure_core_amqp/src/management.rs @@ -7,7 +7,6 @@ use super::{ value::{AmqpOrderedMap, AmqpValue}, }; use azure_core::{credentials::AccessToken, error::Result}; -use std::fmt::Debug; #[cfg(all(feature = "fe2o3-amqp", not(target_arch = "wasm32")))] type ManagementImplementation = super::fe2o3::management::Fe2o3AmqpManagement; @@ -27,7 +26,6 @@ pub trait AmqpManagementApis { ) -> impl std::future::Future>>; } -#[derive(Debug)] pub struct AmqpManagement { implementation: ManagementImplementation, } diff --git a/sdk/core/azure_core_amqp/src/noop.rs b/sdk/core/azure_core_amqp/src/noop.rs index ef1dd1899f..d3cd4c5f68 100644 --- a/sdk/core/azure_core_amqp/src/noop.rs +++ b/sdk/core/azure_core_amqp/src/noop.rs @@ -16,22 +16,22 @@ use super::{ use azure_core::{credentials::AccessToken, error::Result}; use std::marker::PhantomData; -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct NoopAmqpConnection {} -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct NoopAmqpManagement {} -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct NoopAmqpSender {} -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct NoopAmqpReceiver {} -#[derive(Debug, Default, Clone)] +#[derive(Default, Clone)] pub(crate) struct NoopAmqpSession {} -#[derive(Debug, Default)] +#[derive(Default)] pub(crate) struct NoopAmqpClaimsBasedSecurity<'a> { phantom: PhantomData<&'a AmqpSession>, } diff --git a/sdk/core/azure_core_amqp/src/receiver.rs b/sdk/core/azure_core_amqp/src/receiver.rs index ab8f7e4f67..7cf16a5214 100644 --- a/sdk/core/azure_core_amqp/src/receiver.rs +++ b/sdk/core/azure_core_amqp/src/receiver.rs @@ -87,7 +87,7 @@ pub trait AmqpReceiverApis { fn receive(&self) -> impl std::future::Future>; } -#[derive(Debug, Default)] +#[derive(Default)] pub struct AmqpReceiver { implementation: ReceiverImplementation, } @@ -213,7 +213,7 @@ mod tests { ); assert!(receiver_options.properties.is_some()); let properties = receiver_options.properties.clone().unwrap(); - assert!(properties.contains_key("key".into())); + assert!(properties.contains_key(&AmqpSymbol::from("key").into())); assert_eq!( *properties.get("key".into()).unwrap(), AmqpValue::String("value".to_string()) diff --git a/sdk/core/azure_core_amqp/src/sender.rs b/sdk/core/azure_core_amqp/src/sender.rs index 4bf336b8c9..a8f8efeea5 100644 --- a/sdk/core/azure_core_amqp/src/sender.rs +++ b/sdk/core/azure_core_amqp/src/sender.rs @@ -49,7 +49,7 @@ pub trait AmqpSenderApis { ) -> impl std::future::Future>; } -#[derive(Debug, Default)] +#[derive(Default)] pub struct AmqpSender { implementation: SenderImplementation, } @@ -245,7 +245,7 @@ mod tests { ); assert!(sender_options.properties.is_some()); let properties = sender_options.properties.clone().unwrap(); - assert!(properties.contains_key("key".into())); + assert!(properties.contains_key(&AmqpSymbol::from("key"))); assert_eq!( *properties.get("key".into()).unwrap(), AmqpValue::String("value".to_string()) diff --git a/sdk/core/azure_core_amqp/src/session.rs b/sdk/core/azure_core_amqp/src/session.rs index 6c770140a7..f1fbe730e4 100644 --- a/sdk/core/azure_core_amqp/src/session.rs +++ b/sdk/core/azure_core_amqp/src/session.rs @@ -75,7 +75,7 @@ pub trait AmqpSessionApis { fn end(&self) -> impl std::future::Future>; } -#[derive(Debug, Clone, Default)] +#[derive(Clone, Default)] pub struct AmqpSession { pub(crate) implementation: SessionImplementation, } @@ -192,7 +192,7 @@ mod tests { ); assert!(session_options.properties.is_some()); let properties = session_options.properties.clone().unwrap(); - assert!(properties.contains_key("key".into())); + assert!(properties.contains_key(&AmqpSymbol::from("key"))); assert_eq!( *properties.get("key".into()).unwrap(), AmqpValue::String("value".to_string()) diff --git a/sdk/core/azure_core_amqp/src/value.rs b/sdk/core/azure_core_amqp/src/value.rs index 9d8a4a5c22..b1760d7dcf 100644 --- a/sdk/core/azure_core_amqp/src/value.rs +++ b/sdk/core/azure_core_amqp/src/value.rs @@ -76,11 +76,17 @@ impl From> for AmqpList { } } -/// AMQP Timestamp. Number of milliseconds since UNIX_EPOCH. +/// AMQP Timestamp. /// -/// NOTE: This can also contain the value of -62_135_596_800_000 which is +/// Represents a point in time. +/// +/// Note: Internally, AMQP times are represented as signed milliseconds since +/// the UNIX epoch (1-1-1970). +/// +/// They can also contain the value of -62_135_596_800_000 which is /// January 1, 0001 represented as the number of milliseconds *BEFORE* the UNIX_EPOCH. -/// This time cannot be expressed as a SystemTime. +/// +/// This time cannot be expressed as a `SystemTime`, so it is represented as `None`. #[derive(Debug, PartialEq, Clone)] pub struct AmqpTimestamp(pub Option); @@ -280,7 +286,7 @@ where Some(self.inner.remove(index).1) } - pub fn contains_key(&self, key: K) -> bool { + pub fn contains_key(&self, key: &K) -> bool { self.inner.iter().any(|(k, _)| *k == key.clone()) } diff --git a/sdk/eventhubs/azure_messaging_eventhubs/README.md b/sdk/eventhubs/azure_messaging_eventhubs/README.md index 419396a44b..8b693400d8 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/README.md +++ b/sdk/eventhubs/azure_messaging_eventhubs/README.md @@ -223,8 +223,10 @@ async fn receive_events() { azure_messaging_eventhubs::consumer::ReceiveOptions{ start_position: Some(azure_messaging_eventhubs::consumer::StartPosition{ location: azure_messaging_eventhubs::consumer::StartLocation::Earliest, - ..Default::default()}), - ..Default::default()}, + ..Default::default() + }), + ..Default::default() + }, )) .await; diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs index cabfdd63a2..c1dccfb609 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs @@ -15,7 +15,6 @@ use std::time::SystemTime; pub(crate) mod user_agent; -#[derive(Debug)] pub(crate) struct ManagementInstance { pub management: AmqpManagement, } @@ -53,7 +52,7 @@ impl ManagementInstance { .call(EVENTHUB_ENTITY_TYPE.to_string(), application_properties) .await?; - if !response.contains_key(EVENTHUB_PROPERTY_PARTITION_COUNT.to_string()) { + if !response.contains_key(&EVENTHUB_PROPERTY_PARTITION_COUNT.to_string()) { return Err(ErrorKind::InvalidManagementResponse.into()); } let name: String = response @@ -107,9 +106,9 @@ impl ManagementInstance { .await?; // Look for the required response properties - if !response.contains_key(EVENTHUB_PARTITION_PROPERTIES_TYPE.to_string()) + if !response.contains_key(&EVENTHUB_PARTITION_PROPERTIES_TYPE.to_string()) || !response.contains_key( - EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER_EPOCH.to_string(), + &EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER_EPOCH.to_string(), ) { return Err(ErrorKind::InvalidManagementResponse.into()); diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs index d6d11c2cac..c470e09a01 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs @@ -40,7 +40,6 @@ use tracing::{debug, trace}; use url::Url; /// A client that can be used to receive events from an Event Hub. -#[derive(Debug)] pub struct ConsumerClient { options: ConsumerClientOptions, session_instances: Mutex>>, @@ -80,7 +79,6 @@ impl ConsumerClient { /// let consumer = ConsumerClient::new("my_namespace".to_string(), "my_eventhub".to_string(), None, my_credential, None); /// # Ok(())} /// ``` - #[tracing::instrument] pub fn new( fully_qualified_namespace: String, eventhub_name: String, @@ -139,7 +137,6 @@ impl ConsumerClient { /// } /// } /// ``` - #[tracing::instrument] pub async fn open(&self) -> Result<()> { self.ensure_connection(&self.url).await?; Ok(()) @@ -183,7 +180,6 @@ impl ConsumerClient { /// } /// } /// ``` - #[tracing::instrument] pub async fn close(self) -> Result<()> { self.connection .get() @@ -240,7 +236,6 @@ impl ConsumerClient { /// } /// } /// ``` - #[tracing::instrument] pub async fn receive_events_on_partition( &self, partition_id: String, @@ -333,7 +328,6 @@ impl ConsumerClient { /// } /// } /// ``` - #[tracing::instrument] pub async fn get_eventhub_properties(&self) -> Result { self.ensure_management_client().await?; @@ -385,7 +379,6 @@ impl ConsumerClient { /// } /// } /// ``` - #[tracing::instrument] pub async fn get_partition_properties( &self, partition_id: String, @@ -401,7 +394,6 @@ impl ConsumerClient { .await } - #[tracing::instrument] async fn ensure_management_client(&self) -> Result<()> { trace!("Ensure management client."); @@ -443,7 +435,6 @@ impl ConsumerClient { Ok(()) } - #[tracing::instrument] async fn ensure_connection(&self, url: &String) -> Result<()> { if self.connection.get().is_none() { let connection = AmqpConnection::new(); @@ -538,7 +529,7 @@ impl ConsumerClient { .get(partition_id) .ok_or_else(|| azure_core::Error::from(ErrorKind::MissingSession))? .clone(); - debug!("Cloning session for partition {:?}: {:?}", partition_id, rv); + debug!("Cloning session for partition {:?}", partition_id); Ok(rv) } } From 094575bb3d7a6ca4debd948a8d17cb979eac47e3 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Wed, 6 Nov 2024 14:31:45 -0800 Subject: [PATCH 07/11] PR feedback - AmqpOrderedMap::get takes a reference to key, not a captured key; Removed several requirements on AmqpOrderedMap K and V --- sdk/core/azure_core_amqp/src/connection.rs | 40 +++++++++---------- sdk/core/azure_core_amqp/src/receiver.rs | 6 ++- sdk/core/azure_core_amqp/src/sender.rs | 2 +- sdk/core/azure_core_amqp/src/session.rs | 6 +-- sdk/core/azure_core_amqp/src/value.rs | 36 ++++++++--------- .../src/common/mod.rs | 20 +++++----- 6 files changed, 56 insertions(+), 54 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/connection.rs b/sdk/core/azure_core_amqp/src/connection.rs index ac2a91bc24..e73edd20f3 100644 --- a/sdk/core/azure_core_amqp/src/connection.rs +++ b/sdk/core/azure_core_amqp/src/connection.rs @@ -30,32 +30,32 @@ impl AmqpConnectionOptions { pub fn builder() -> builders::AmqpConnectionOptionsBuilder { builders::AmqpConnectionOptionsBuilder::new() } - pub fn max_frame_size(&self) -> Option { - self.max_frame_size + pub fn max_frame_size(&self) -> Option<&u32> { + self.max_frame_size.as_ref() } - pub fn channel_max(&self) -> Option { - self.channel_max + pub fn channel_max(&self) -> Option<&u16> { + self.channel_max.as_ref() } - pub fn idle_timeout(&self) -> Option { - self.idle_timeout + pub fn idle_timeout(&self) -> Option<&Duration> { + self.idle_timeout.as_ref() } - pub fn outgoing_locales(&self) -> Option> { - self.outgoing_locales.clone() + pub fn outgoing_locales(&self) -> Option<&Vec> { + self.outgoing_locales.as_ref() } - pub fn incoming_locales(&self) -> Option> { - self.incoming_locales.clone() + pub fn incoming_locales(&self) -> Option<&Vec> { + self.incoming_locales.as_ref() } - pub fn offered_capabilities(&self) -> Option> { - self.offered_capabilities.clone() + pub fn offered_capabilities(&self) -> Option<&Vec> { + self.offered_capabilities.as_ref() } - pub fn desired_capabilities(&self) -> Option> { - self.desired_capabilities.clone() + pub fn desired_capabilities(&self) -> Option<&Vec> { + self.desired_capabilities.as_ref() } - pub fn properties(&self) -> Option> { - self.properties.clone() + pub fn properties(&self) -> Option<&AmqpOrderedMap> { + self.properties.as_ref() } - pub fn buffer_size(&self) -> Option { - self.buffer_size + pub fn buffer_size(&self) -> Option<&usize> { + self.buffer_size.as_ref() } } @@ -156,8 +156,8 @@ pub mod builders { } pub fn with_properties(mut self, properties: impl Into>) -> Self where - K: Into + Debug + Default + PartialEq, - V: Into + Debug + Default, + K: Into + Debug + Clone + PartialEq, + V: Into + Debug + Clone, { let properties_map: AmqpOrderedMap = properties.into(); let properties_map = properties_map diff --git a/sdk/core/azure_core_amqp/src/receiver.rs b/sdk/core/azure_core_amqp/src/receiver.rs index 7cf16a5214..c76a84b0e6 100644 --- a/sdk/core/azure_core_amqp/src/receiver.rs +++ b/sdk/core/azure_core_amqp/src/receiver.rs @@ -215,7 +215,7 @@ mod tests { let properties = receiver_options.properties.clone().unwrap(); assert!(properties.contains_key(&AmqpSymbol::from("key").into())); assert_eq!( - *properties.get("key".into()).unwrap(), + *properties.get(&AmqpSymbol::from("key")).unwrap(), AmqpValue::String("value".to_string()) ); } @@ -303,7 +303,9 @@ mod tests { assert!(receiver_options.properties.is_some()); let properties_option = receiver_options.properties.unwrap(); assert_eq!( - *properties_option.get("combo_key".into()).unwrap(), + *properties_option + .get(&AmqpSymbol::from("combo_key")) + .unwrap(), AmqpValue::String("combo_value".to_string()) ); assert_eq!( diff --git a/sdk/core/azure_core_amqp/src/sender.rs b/sdk/core/azure_core_amqp/src/sender.rs index a8f8efeea5..312d06c43a 100644 --- a/sdk/core/azure_core_amqp/src/sender.rs +++ b/sdk/core/azure_core_amqp/src/sender.rs @@ -247,7 +247,7 @@ mod tests { let properties = sender_options.properties.clone().unwrap(); assert!(properties.contains_key(&AmqpSymbol::from("key"))); assert_eq!( - *properties.get("key".into()).unwrap(), + *properties.get(&AmqpSymbol::from("key")).unwrap(), AmqpValue::String("value".to_string()) ); diff --git a/sdk/core/azure_core_amqp/src/session.rs b/sdk/core/azure_core_amqp/src/session.rs index f1fbe730e4..9b021778f2 100644 --- a/sdk/core/azure_core_amqp/src/session.rs +++ b/sdk/core/azure_core_amqp/src/session.rs @@ -144,8 +144,8 @@ pub mod builders { } pub fn with_properties(mut self, properties: impl Into>) -> Self where - K: Into + PartialEq + Default + Debug, - V: Into + Default, + K: Into + PartialEq + Clone + Debug, + V: Into + Clone, { let properties_map: AmqpOrderedMap = properties .into() @@ -194,7 +194,7 @@ mod tests { let properties = session_options.properties.clone().unwrap(); assert!(properties.contains_key(&AmqpSymbol::from("key"))); assert_eq!( - *properties.get("key".into()).unwrap(), + *properties.get(&AmqpSymbol::from("key")).unwrap(), AmqpValue::String("value".to_string()) ); diff --git a/sdk/core/azure_core_amqp/src/value.rs b/sdk/core/azure_core_amqp/src/value.rs index b1760d7dcf..b8deb37693 100644 --- a/sdk/core/azure_core_amqp/src/value.rs +++ b/sdk/core/azure_core_amqp/src/value.rs @@ -99,8 +99,8 @@ impl From for AmqpTimestamp { #[derive(Debug, PartialEq, Clone, Default)] pub struct AmqpOrderedMap where - K: PartialEq + Default, - V: Default, + K: PartialEq, + V: Clone, { inner: Vec<(K, V)>, } @@ -256,8 +256,8 @@ impl Deserializable for AmqpValue { impl AmqpOrderedMap where - K: PartialEq + Clone + Default, - V: Clone + Default, + K: PartialEq + Clone, + V: Clone, { pub fn new() -> Self { Self { inner: Vec::new() } @@ -267,10 +267,10 @@ where self.inner.push((key, value)); } - pub fn get(&self, key: K) -> Option<&V> { + pub fn get(&self, key: &K) -> Option<&V> { self.inner .iter() - .find_map(|(k, v)| if *k == key.clone() { Some(v) } else { None }) + .find_map(|(k, v)| if k == key { Some(v) } else { None }) } pub fn len(&self) -> usize { @@ -287,7 +287,7 @@ where } pub fn contains_key(&self, key: &K) -> bool { - self.inner.iter().any(|(k, _)| *k == key.clone()) + self.inner.iter().any(|(k, _)| k == key) } pub fn iter(&self) -> impl Iterator + '_ { @@ -297,8 +297,8 @@ where impl IntoIterator for AmqpOrderedMap where - K: PartialEq + Default, - V: Default, + K: PartialEq, + V: Clone, { type Item = (K, V); type IntoIter = as IntoIterator>::IntoIter; @@ -426,8 +426,8 @@ impl From> for AmqpValue { impl From> for AmqpOrderedMap where - K: PartialEq + Default, - V: Default, + K: PartialEq, + V: Clone, { fn from(v: Vec<(K, V)>) -> Self { AmqpOrderedMap { @@ -438,8 +438,8 @@ where impl FromIterator<(K, V)> for AmqpOrderedMap where - K: PartialEq + Default, - V: Default, + K: PartialEq, + V: Clone, { fn from_iter>(iter: I) -> Self { AmqpOrderedMap { @@ -625,14 +625,14 @@ mod tests { map.insert("key2", 2); map.insert("key3", 3); - assert_eq!(map.get("key1"), Some(&1)); - assert_eq!(map.get("key2"), Some(&2)); - assert_eq!(map.get("key3"), Some(&3)); - assert_eq!(map.get("key4"), None); + assert_eq!(map.get(&"key1"), Some(&1)); + assert_eq!(map.get(&"key2"), Some(&2)); + assert_eq!(map.get(&"key3"), Some(&3)); + assert_eq!(map.get(&"key4"), None); assert_eq!(map.remove(&"key1"), Some(1)); assert_eq!(map.remove(&"key1"), None); - assert_eq!(map.get("key1"), None); + assert_eq!(map.get(&"key1"), None); } #[allow(clippy::approx_constant)] diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs index c1dccfb609..36bb4218fa 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs @@ -56,13 +56,13 @@ impl ManagementInstance { return Err(ErrorKind::InvalidManagementResponse.into()); } let name: String = response - .get(EVENTHUB_PROPERTY_NAME.into()) + .get(&EVENTHUB_PROPERTY_NAME.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(); let created_at: Option = Into::::into( response - .get(EVENTHUB_PROPERTY_CREATED_AT.into()) + .get(&EVENTHUB_PROPERTY_CREATED_AT.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone(), ) @@ -71,7 +71,7 @@ impl ManagementInstance { // Into::::into(response.get("partition_count".to_string()).ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))?.clone()); let partition_ids = response - .get(EVENTHUB_PROPERTY_PARTITION_IDS.into()) + .get(&EVENTHUB_PROPERTY_PARTITION_IDS.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))?; let partition_ids = match partition_ids { @@ -116,40 +116,40 @@ impl ManagementInstance { Ok(EventHubPartitionProperties { beginning_sequence_number: response - .get(EVENTHUB_PARTITION_PROPERTIES_BEGIN_SEQUENCE_NUMBER.into()) + .get(&EVENTHUB_PARTITION_PROPERTIES_BEGIN_SEQUENCE_NUMBER.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), id: response - .get(EVENTHUB_PROPERTY_PARTITION.into()) + .get(&EVENTHUB_PROPERTY_PARTITION.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), eventhub: response - .get(EVENTHUB_PROPERTY_NAME.into()) + .get(&EVENTHUB_PROPERTY_NAME.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_sequence_number: response - .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER.into()) + .get(&EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_offset: response - .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_OFFSET.into()) + .get(&EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_OFFSET.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_time_utc: Into::::into( response - .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_TIME_UTC.into()) + .get(&EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_TIME_UTC.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone(), ) .0, is_empty: response - .get(EVENTHUB_PARTITION_PROPERTIES_IS_EMPTY.into()) + .get(&EVENTHUB_PARTITION_PROPERTIES_IS_EMPTY.into()) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), From 2247665577d570d12cf9fd1eaae0c3ee8a5772b2 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Wed, 6 Nov 2024 17:23:27 -0800 Subject: [PATCH 08/11] clippy fixes --- sdk/core/azure_core_amqp/src/receiver.rs | 2 +- .../azure_messaging_eventhubs/src/consumer/mod.rs | 7 ++----- .../azure_messaging_eventhubs/src/producer/batch.rs | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/receiver.rs b/sdk/core/azure_core_amqp/src/receiver.rs index c76a84b0e6..6d60a95318 100644 --- a/sdk/core/azure_core_amqp/src/receiver.rs +++ b/sdk/core/azure_core_amqp/src/receiver.rs @@ -213,7 +213,7 @@ mod tests { ); assert!(receiver_options.properties.is_some()); let properties = receiver_options.properties.clone().unwrap(); - assert!(properties.contains_key(&AmqpSymbol::from("key").into())); + assert!(properties.contains_key(&AmqpSymbol::from("key"))); assert_eq!( *properties.get(&AmqpSymbol::from("key")).unwrap(), AmqpValue::String("value".to_string()) diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs index c470e09a01..d1e9f20417 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/consumer/mod.rs @@ -435,7 +435,7 @@ impl ConsumerClient { Ok(()) } - async fn ensure_connection(&self, url: &String) -> Result<()> { + async fn ensure_connection(&self, url: &str) -> Result<()> { if self.connection.get().is_none() { let connection = AmqpConnection::new(); connection @@ -751,7 +751,6 @@ mod tests { let start_position = StartPosition { location: StartLocation::SequenceNumber(sequence_number), inclusive: true, - ..Default::default() }; assert_eq!( StartPosition::start_expression(&Some(start_position)), @@ -783,7 +782,7 @@ mod tests { start_position.location, StartLocation::EnqueuedTime(enqueued_time) ); - assert_eq!(start_position.inclusive, false); + assert!(!start_position.inclusive); assert_eq!( StartPosition::start_expression(&Some(start_position)), format!( @@ -798,7 +797,6 @@ mod tests { let start_position = StartPosition { location: StartLocation::EnqueuedTime(enqueued_time), inclusive: true, - ..Default::default() }; assert_eq!( StartPosition::start_expression(&Some(start_position)), @@ -832,7 +830,6 @@ mod tests { let start_position = StartPosition { location: StartLocation::Offset(offset.clone()), inclusive: true, - ..Default::default() }; assert_eq!( "amqp.annotation.x-opt-offset >='12345'", diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs index dd395352ab..4213eed947 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/producer/batch.rs @@ -54,7 +54,6 @@ struct EventDataBatchState { /// ``` pub struct EventDataBatch<'a> { producer: &'a ProducerClient, - batch_state: Mutex, max_size_in_bytes: u64, partition_key: Option, @@ -372,7 +371,6 @@ mod tests { max_size_in_bytes: Some(1024), partition_key: Some("pk".to_string()), partition_id: Some("pid".to_string()), - ..Default::default() }; assert_eq!(options.max_size_in_bytes, Some(1024)); From a599ddcd53bf26c9183cd5ad80de70b7bc0031f0 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Thu, 7 Nov 2024 09:42:38 -0800 Subject: [PATCH 09/11] AmqpOrderedMap contains_key, get, and remove take impl PartialEq rather than &K --- sdk/core/azure_core_amqp/src/receiver.rs | 4 +- sdk/core/azure_core_amqp/src/sender.rs | 4 +- sdk/core/azure_core_amqp/src/session.rs | 2 +- sdk/core/azure_core_amqp/src/value.rs | 44 +++++++++++++------ .../src/common/mod.rs | 29 ++++++------ 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/receiver.rs b/sdk/core/azure_core_amqp/src/receiver.rs index 6d60a95318..89224319e2 100644 --- a/sdk/core/azure_core_amqp/src/receiver.rs +++ b/sdk/core/azure_core_amqp/src/receiver.rs @@ -213,9 +213,9 @@ mod tests { ); assert!(receiver_options.properties.is_some()); let properties = receiver_options.properties.clone().unwrap(); - assert!(properties.contains_key(&AmqpSymbol::from("key"))); + assert!(properties.contains_key("key")); assert_eq!( - *properties.get(&AmqpSymbol::from("key")).unwrap(), + *properties.get("key").unwrap(), AmqpValue::String("value".to_string()) ); } diff --git a/sdk/core/azure_core_amqp/src/sender.rs b/sdk/core/azure_core_amqp/src/sender.rs index 312d06c43a..14bb6337d4 100644 --- a/sdk/core/azure_core_amqp/src/sender.rs +++ b/sdk/core/azure_core_amqp/src/sender.rs @@ -245,9 +245,9 @@ mod tests { ); assert!(sender_options.properties.is_some()); let properties = sender_options.properties.clone().unwrap(); - assert!(properties.contains_key(&AmqpSymbol::from("key"))); + assert!(properties.contains_key("key")); assert_eq!( - *properties.get(&AmqpSymbol::from("key")).unwrap(), + *properties.get("key").unwrap(), AmqpValue::String("value".to_string()) ); diff --git a/sdk/core/azure_core_amqp/src/session.rs b/sdk/core/azure_core_amqp/src/session.rs index 9b021778f2..45dd988de5 100644 --- a/sdk/core/azure_core_amqp/src/session.rs +++ b/sdk/core/azure_core_amqp/src/session.rs @@ -192,7 +192,7 @@ mod tests { ); assert!(session_options.properties.is_some()); let properties = session_options.properties.clone().unwrap(); - assert!(properties.contains_key(&AmqpSymbol::from("key"))); + assert!(properties.contains_key("key")); assert_eq!( *properties.get(&AmqpSymbol::from("key")).unwrap(), AmqpValue::String("value".to_string()) diff --git a/sdk/core/azure_core_amqp/src/value.rs b/sdk/core/azure_core_amqp/src/value.rs index b8deb37693..c2d8309095 100644 --- a/sdk/core/azure_core_amqp/src/value.rs +++ b/sdk/core/azure_core_amqp/src/value.rs @@ -24,6 +24,24 @@ impl PartialEq<&str> for AmqpSymbol { } } +impl PartialEq for &str { + fn eq(&self, other: &AmqpSymbol) -> bool { + *self == other.0 + } +} + +impl PartialEq<&AmqpSymbol> for AmqpSymbol { + fn eq(&self, other: &&AmqpSymbol) -> bool { + self.0 == other.0 + } +} + +impl PartialEq for &AmqpSymbol { + fn eq(&self, other: &AmqpSymbol) -> bool { + self.0 == other.0 + } +} + impl From for AmqpSymbol { fn from(s: String) -> Self { AmqpSymbol(s) @@ -267,10 +285,10 @@ where self.inner.push((key, value)); } - pub fn get(&self, key: &K) -> Option<&V> { + pub fn get(&self, key: impl PartialEq) -> Option<&V> { self.inner .iter() - .find_map(|(k, v)| if k == key { Some(v) } else { None }) + .find_map(|(k, v)| if key == *k { Some(v) } else { None }) } pub fn len(&self) -> usize { @@ -281,13 +299,13 @@ where self.inner.is_empty() } - pub fn remove(&mut self, key: &K) -> Option { - let index = self.inner.iter().position(|(k, _)| k == key)?; + pub fn remove(&mut self, key: impl PartialEq) -> Option { + let index = self.inner.iter().position(|(k, _)| key == *k)?; Some(self.inner.remove(index).1) } - pub fn contains_key(&self, key: &K) -> bool { - self.inner.iter().any(|(k, _)| k == key) + pub fn contains_key(&self, key: impl PartialEq) -> bool { + self.inner.iter().any(|(k, _)| key == *k) } pub fn iter(&self) -> impl Iterator + '_ { @@ -625,14 +643,14 @@ mod tests { map.insert("key2", 2); map.insert("key3", 3); - assert_eq!(map.get(&"key1"), Some(&1)); - assert_eq!(map.get(&"key2"), Some(&2)); - assert_eq!(map.get(&"key3"), Some(&3)); - assert_eq!(map.get(&"key4"), None); + assert_eq!(map.get("key1"), Some(&1)); + assert_eq!(map.get("key2"), Some(&2)); + assert_eq!(map.get("key3"), Some(&3)); + assert_eq!(map.get("key4"), None); - assert_eq!(map.remove(&"key1"), Some(1)); - assert_eq!(map.remove(&"key1"), None); - assert_eq!(map.get(&"key1"), None); + assert_eq!(map.remove("key1"), Some(1)); + assert_eq!(map.remove("key1"), None); + assert_eq!(map.get("key1"), None); } #[allow(clippy::approx_constant)] diff --git a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs index 36bb4218fa..ce7523c0a8 100644 --- a/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs +++ b/sdk/eventhubs/azure_messaging_eventhubs/src/common/mod.rs @@ -52,17 +52,17 @@ impl ManagementInstance { .call(EVENTHUB_ENTITY_TYPE.to_string(), application_properties) .await?; - if !response.contains_key(&EVENTHUB_PROPERTY_PARTITION_COUNT.to_string()) { + if !response.contains_key(EVENTHUB_PROPERTY_PARTITION_COUNT) { return Err(ErrorKind::InvalidManagementResponse.into()); } let name: String = response - .get(&EVENTHUB_PROPERTY_NAME.into()) + .get(EVENTHUB_PROPERTY_NAME) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(); let created_at: Option = Into::::into( response - .get(&EVENTHUB_PROPERTY_CREATED_AT.into()) + .get(EVENTHUB_PROPERTY_CREATED_AT) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone(), ) @@ -71,7 +71,7 @@ impl ManagementInstance { // Into::::into(response.get("partition_count".to_string()).ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))?.clone()); let partition_ids = response - .get(&EVENTHUB_PROPERTY_PARTITION_IDS.into()) + .get(EVENTHUB_PROPERTY_PARTITION_IDS) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))?; let partition_ids = match partition_ids { @@ -106,50 +106,49 @@ impl ManagementInstance { .await?; // Look for the required response properties - if !response.contains_key(&EVENTHUB_PARTITION_PROPERTIES_TYPE.to_string()) - || !response.contains_key( - &EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER_EPOCH.to_string(), - ) + if !response.contains_key(EVENTHUB_PARTITION_PROPERTIES_TYPE) + || !response + .contains_key(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER_EPOCH) { return Err(ErrorKind::InvalidManagementResponse.into()); } Ok(EventHubPartitionProperties { beginning_sequence_number: response - .get(&EVENTHUB_PARTITION_PROPERTIES_BEGIN_SEQUENCE_NUMBER.into()) + .get(EVENTHUB_PARTITION_PROPERTIES_BEGIN_SEQUENCE_NUMBER) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), id: response - .get(&EVENTHUB_PROPERTY_PARTITION.into()) + .get(EVENTHUB_PROPERTY_PARTITION) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), eventhub: response - .get(&EVENTHUB_PROPERTY_NAME.into()) + .get(EVENTHUB_PROPERTY_NAME) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_sequence_number: response - .get(&EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER.into()) + .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_SEQUENCE_NUMBER) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_offset: response - .get(&EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_OFFSET.into()) + .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_OFFSET) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), last_enqueued_time_utc: Into::::into( response - .get(&EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_TIME_UTC.into()) + .get(EVENTHUB_PARTITION_PROPERTIES_LAST_ENQUEUED_TIME_UTC) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone(), ) .0, is_empty: response - .get(&EVENTHUB_PARTITION_PROPERTIES_IS_EMPTY.into()) + .get(EVENTHUB_PARTITION_PROPERTIES_IS_EMPTY) .ok_or_else(|| azure_core::Error::from(ErrorKind::InvalidManagementResponse))? .clone() .into(), From fb4d1b8f7662c5820a247ea703b1f3a2ca7758f2 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Thu, 7 Nov 2024 16:59:40 -0800 Subject: [PATCH 10/11] PR feedback redux --- sdk/core/azure_core_amqp/src/connection.rs | 12 ++--- sdk/core/azure_core_amqp/src/session.rs | 2 +- sdk/core/azure_core_amqp/src/value.rs | 59 +++++++++++++++++----- 3 files changed, 52 insertions(+), 21 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/connection.rs b/sdk/core/azure_core_amqp/src/connection.rs index e73edd20f3..a52c2b8cde 100644 --- a/sdk/core/azure_core_amqp/src/connection.rs +++ b/sdk/core/azure_core_amqp/src/connection.rs @@ -30,11 +30,11 @@ impl AmqpConnectionOptions { pub fn builder() -> builders::AmqpConnectionOptionsBuilder { builders::AmqpConnectionOptionsBuilder::new() } - pub fn max_frame_size(&self) -> Option<&u32> { - self.max_frame_size.as_ref() + pub fn max_frame_size(&self) -> Option { + self.max_frame_size } - pub fn channel_max(&self) -> Option<&u16> { - self.channel_max.as_ref() + pub fn channel_max(&self) -> Option { + self.channel_max } pub fn idle_timeout(&self) -> Option<&Duration> { self.idle_timeout.as_ref() @@ -54,8 +54,8 @@ impl AmqpConnectionOptions { pub fn properties(&self) -> Option<&AmqpOrderedMap> { self.properties.as_ref() } - pub fn buffer_size(&self) -> Option<&usize> { - self.buffer_size.as_ref() + pub fn buffer_size(&self) -> Option { + self.buffer_size } } diff --git a/sdk/core/azure_core_amqp/src/session.rs b/sdk/core/azure_core_amqp/src/session.rs index 45dd988de5..0b3e232860 100644 --- a/sdk/core/azure_core_amqp/src/session.rs +++ b/sdk/core/azure_core_amqp/src/session.rs @@ -144,7 +144,7 @@ pub mod builders { } pub fn with_properties(mut self, properties: impl Into>) -> Self where - K: Into + PartialEq + Clone + Debug, + K: Into + PartialEq + Clone, V: Into + Clone, { let properties_map: AmqpOrderedMap = properties diff --git a/sdk/core/azure_core_amqp/src/value.rs b/sdk/core/azure_core_amqp/src/value.rs index c2d8309095..a465f1ecc8 100644 --- a/sdk/core/azure_core_amqp/src/value.rs +++ b/sdk/core/azure_core_amqp/src/value.rs @@ -2,6 +2,8 @@ // Licensed under the MIT license. // cspell: words amqp +use std::borrow::Borrow; + use crate::Uuid; #[cfg(all( @@ -18,12 +20,23 @@ use azure_core::Result; #[derive(Debug, PartialEq, Clone, Default, Eq)] pub struct AmqpSymbol(pub String); +impl PartialEq for AmqpSymbol { + fn eq(&self, other: &str) -> bool { + self.0.as_str() == other + } +} + +impl PartialEq for str { + fn eq(&self, other: &AmqpSymbol) -> bool { + self == other.0.as_str() + } +} + impl PartialEq<&str> for AmqpSymbol { fn eq(&self, other: &&str) -> bool { self.0 == *other } } - impl PartialEq for &str { fn eq(&self, other: &AmqpSymbol) -> bool { *self == other.0 @@ -59,6 +72,12 @@ impl From<&str> for AmqpSymbol { } } +impl Borrow for AmqpSymbol { + fn borrow(&self) -> &str { + self.0.as_str() + } +} + #[derive(Debug, PartialEq, Clone, Default)] pub struct AmqpList(pub Vec); @@ -285,10 +304,14 @@ where self.inner.push((key, value)); } - pub fn get(&self, key: impl PartialEq) -> Option<&V> { + pub fn get(&self, key: &Q) -> Option<&V> + where + K: Borrow + PartialEq, + Q: PartialEq + ?Sized, + { self.inner .iter() - .find_map(|(k, v)| if key == *k { Some(v) } else { None }) + .find_map(|(k, v)| if key == k { Some(v) } else { None }) } pub fn len(&self) -> usize { @@ -299,13 +322,21 @@ where self.inner.is_empty() } - pub fn remove(&mut self, key: impl PartialEq) -> Option { - let index = self.inner.iter().position(|(k, _)| key == *k)?; + pub fn remove(&mut self, key: &Q) -> Option + where + K: Borrow + PartialEq, + Q: PartialEq + ?Sized, + { + let index = self.inner.iter().position(|(k, _)| key == k)?; Some(self.inner.remove(index).1) } - pub fn contains_key(&self, key: impl PartialEq) -> bool { - self.inner.iter().any(|(k, _)| key == *k) + pub fn contains_key(&self, key: &Q) -> bool + where + K: Borrow + PartialEq, + Q: PartialEq + ?Sized, + { + self.inner.iter().any(|(k, _)| key == k) } pub fn iter(&self) -> impl Iterator + '_ { @@ -643,14 +674,14 @@ mod tests { map.insert("key2", 2); map.insert("key3", 3); - assert_eq!(map.get("key1"), Some(&1)); - assert_eq!(map.get("key2"), Some(&2)); - assert_eq!(map.get("key3"), Some(&3)); - assert_eq!(map.get("key4"), None); + assert_eq!(map.get(&"key1"), Some(&1)); + assert_eq!(map.get(&"key2"), Some(&2)); + assert_eq!(map.get(&"key3"), Some(&3)); + assert_eq!(map.get(&"key4"), None); - assert_eq!(map.remove("key1"), Some(1)); - assert_eq!(map.remove("key1"), None); - assert_eq!(map.get("key1"), None); + assert_eq!(map.remove(&"key1"), Some(1)); + assert_eq!(map.remove(&"key1"), None); + assert_eq!(map.get(&"key1"), None); } #[allow(clippy::approx_constant)] From 43e36e04bfe68b6079efa3c63150617c93e82049 Mon Sep 17 00:00:00 2001 From: Larry Osterman Date: Fri, 8 Nov 2024 09:48:30 -0800 Subject: [PATCH 11/11] Get, remove, contains_key don't require symmetrical eq --- sdk/core/azure_core_amqp/src/value.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/sdk/core/azure_core_amqp/src/value.rs b/sdk/core/azure_core_amqp/src/value.rs index a465f1ecc8..337568b99a 100644 --- a/sdk/core/azure_core_amqp/src/value.rs +++ b/sdk/core/azure_core_amqp/src/value.rs @@ -20,11 +20,11 @@ use azure_core::Result; #[derive(Debug, PartialEq, Clone, Default, Eq)] pub struct AmqpSymbol(pub String); -impl PartialEq for AmqpSymbol { - fn eq(&self, other: &str) -> bool { - self.0.as_str() == other - } -} +// impl PartialEq for AmqpSymbol { +// fn eq(&self, other: &str) -> bool { +// self.0.as_str() == other +// } +// } impl PartialEq for str { fn eq(&self, other: &AmqpSymbol) -> bool { @@ -306,12 +306,12 @@ where pub fn get(&self, key: &Q) -> Option<&V> where - K: Borrow + PartialEq, + K: Borrow, Q: PartialEq + ?Sized, { self.inner .iter() - .find_map(|(k, v)| if key == k { Some(v) } else { None }) + .find_map(|(k, v)| if key.eq(k) { Some(v) } else { None }) } pub fn len(&self) -> usize { @@ -324,19 +324,19 @@ where pub fn remove(&mut self, key: &Q) -> Option where - K: Borrow + PartialEq, + K: Borrow, Q: PartialEq + ?Sized, { - let index = self.inner.iter().position(|(k, _)| key == k)?; + let index = self.inner.iter().position(|(k, _)| key.eq(k))?; Some(self.inner.remove(index).1) } pub fn contains_key(&self, key: &Q) -> bool where - K: Borrow + PartialEq, + K: Borrow, Q: PartialEq + ?Sized, { - self.inner.iter().any(|(k, _)| key == k) + self.inner.iter().any(|(k, _)| key.eq(k)) } pub fn iter(&self) -> impl Iterator + '_ {