diff --git a/Cargo.lock.msrv b/Cargo.lock.msrv index 05324b38b0..d7f093fd8b 100644 --- a/Cargo.lock.msrv +++ b/Cargo.lock.msrv @@ -65,17 +65,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" -[[package]] -name = "async-trait" -version = "0.1.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.32", -] - [[package]] name = "atty" version = "0.2.14" @@ -1421,7 +1410,6 @@ version = "0.12.0" dependencies = [ "arc-swap", "assert_matches", - "async-trait", "base64", "bigdecimal", "byteorder", @@ -1462,7 +1450,6 @@ dependencies = [ name = "scylla-cql" version = "0.1.0" dependencies = [ - "async-trait", "bigdecimal", "byteorder", "bytes", diff --git a/docs/source/connecting/authentication.md b/docs/source/connecting/authentication.md index 8b60cfecfd..a15296dd70 100644 --- a/docs/source/connecting/authentication.md +++ b/docs/source/connecting/authentication.md @@ -32,49 +32,57 @@ Finally, to make use of the custom authentication, use the `authenticator_provid # extern crate scylla_cql; # extern crate tokio; # extern crate bytes; -# extern crate async_trait; # use std::error::Error; # use std::sync::Arc; +# use std::pin::Pin; +# use std::future::Future; use bytes::{BufMut, BytesMut}; -use async_trait::async_trait; use scylla::authentication::{AuthError, AuthenticatorProvider, AuthenticatorSession}; struct CustomAuthenticator; -#[async_trait] impl AuthenticatorSession for CustomAuthenticator { // to handle an authentication challenge initiated by the server. // The information contained in the token parameter is authentication protocol specific. // It may be NULL or empty. - async fn evaluate_challenge( - &mut self, - _token: Option<&[u8]>, - ) -> Result>, AuthError> { - Err("Challenges are not expected".to_string()) + fn evaluate_challenge<'a>( + &'a mut self, + token: Option<&'a [u8]>, + ) -> Pin>, AuthError>> + Send + 'a>> { + Box::pin(async move { + Err("Challenges are not expected".to_string()) + }) } // to handle the success phase of exchange. The token parameters contain information that may be used to finalize the request. - async fn success(&mut self, _token: Option<&[u8]>) -> Result<(), AuthError> { - Ok(()) + fn success<'a>( + &'a mut self, + token: Option<&'a [u8]> + ) -> Pin> + Send + 'a>> { + Box::pin(async move { Ok(()) }) } } struct CustomAuthenticatorProvider; -#[async_trait] impl AuthenticatorProvider for CustomAuthenticatorProvider { - async fn start_authentication_session( - &self, - _name: &str, - ) -> Result<(Option>, Box), AuthError> { - let mut response = BytesMut::new(); - let cred = "\0cassandra\0cassandra"; - let cred_length = 20; - - response.put_i32(cred_length); - response.put_slice(cred.as_bytes()); - - Ok((Some(response.to_vec()), Box::new(CustomAuthenticator))) + fn start_authentication_session<'a>( + &'a self, + authenticator_name: &'a str, + ) -> Pin>, Box), AuthError>> + Send + 'a>> { + Box::pin(async move { + let mut response = BytesMut::new(); + let cred = "\0cassandra\0cassandra"; + let cred_length = 20; + + response.put_i32(cred_length); + response.put_slice(cred.as_bytes()); + + Ok(( + Some(response.to_vec()), + Box::new(CustomAuthenticator) as Box + )) + }) } } diff --git a/scylla-cql/Cargo.toml b/scylla-cql/Cargo.toml index edbfcd3c8f..28c4e19c68 100644 --- a/scylla-cql/Cargo.toml +++ b/scylla-cql/Cargo.toml @@ -23,7 +23,6 @@ num-bigint-04 = { package = "num-bigint", version = "0.4", optional = true } bigdecimal-04 = { package = "bigdecimal", version = "0.4", optional = true } chrono = { version = "0.4.27", default-features = false, optional = true } lz4_flex = { version = "0.11.1" } -async-trait = "0.1.57" serde = { version = "1.0", features = ["derive"], optional = true } time = { version = "0.3", optional = true } diff --git a/scylla/Cargo.toml b/scylla/Cargo.toml index 665679c8e7..2d85e48e39 100644 --- a/scylla/Cargo.toml +++ b/scylla/Cargo.toml @@ -46,7 +46,6 @@ arc-swap = "1.3.0" dashmap = "5.2" lz4_flex = { version = "0.11.1" } smallvec = "1.8.0" -async-trait = "0.1.56" serde = { version = "1.0", features = ["derive"], optional = true } serde_yaml = { version = "0.9.14", optional = true } url = { version = "2.3.1", optional = true } diff --git a/scylla/src/authentication/mod.rs b/scylla/src/authentication/mod.rs index 2e43b2dee6..f4caf32a19 100644 --- a/scylla/src/authentication/mod.rs +++ b/scylla/src/authentication/mod.rs @@ -1,23 +1,27 @@ -use async_trait::async_trait; use bytes::{BufMut, BytesMut}; +use crate::utils::futures::BoxedFuture; + /// Type to represent an authentication error message. pub type AuthError = String; +/// Type to represent an initial auth response with an authenticator session. +pub(crate) type AuthInitialResponseAndSession = (Option>, Box); + /// Trait used to represent a user-defined custom authentication. -#[async_trait] pub trait AuthenticatorSession: Send + Sync { /// To handle an authentication challenge initiated by the server. /// The information contained in the token parameter is authentication protocol specific. /// It may be NULL or empty. - async fn evaluate_challenge( - &mut self, - token: Option<&[u8]>, - ) -> Result>, AuthError>; + fn evaluate_challenge<'a>( + &'a mut self, + token: Option<&'a [u8]>, + ) -> BoxedFuture<'_, Result>, AuthError>>; /// To handle the success phase of exchange. /// The token parameters contain information that may be used to finalize the request. - async fn success(&mut self, token: Option<&[u8]>) -> Result<(), AuthError>; + fn success<'a>(&'a mut self, token: Option<&'a [u8]>) + -> BoxedFuture<'_, Result<(), AuthError>>; } /// Trait used to represent a factory of [`AuthenticatorSession`] instances. @@ -27,29 +31,32 @@ pub trait AuthenticatorSession: Send + Sync { /// /// Default: [`PlainTextAuthenticator`] is the default authenticator which requires username and /// password. It can be set by using SessionBuilder::user(\"user\", \"pass\") method. -#[async_trait] pub trait AuthenticatorProvider: Sync + Send { /// A pair of initial response and boxed [`AuthenticatorSession`] /// should be returned if authentication is required by the server. - async fn start_authentication_session( - &self, - authenticator_name: &str, - ) -> Result<(Option>, Box), AuthError>; + fn start_authentication_session<'a>( + &'a self, + authenticator_name: &'a str, + ) -> BoxedFuture<'_, Result>; } struct PlainTextAuthenticatorSession; -#[async_trait] impl AuthenticatorSession for PlainTextAuthenticatorSession { - async fn evaluate_challenge( - &mut self, - _token: Option<&[u8]>, - ) -> Result>, AuthError> { - Err("Challenges are not expected during PlainTextAuthentication".to_string()) + fn evaluate_challenge<'a>( + &'a mut self, + _token: Option<&'a [u8]>, + ) -> BoxedFuture<'_, Result>, AuthError>> { + Box::pin(async move { + Err("Challenges are not expected during PlainTextAuthentication".to_string()) + }) } - async fn success(&mut self, _token: Option<&[u8]>) -> Result<(), AuthError> { - Ok(()) + fn success<'a>( + &'a mut self, + _token: Option<&'a [u8]>, + ) -> BoxedFuture<'_, Result<(), AuthError>> { + Box::pin(async move { Ok(()) }) } } @@ -66,24 +73,25 @@ impl PlainTextAuthenticator { } } -#[async_trait] impl AuthenticatorProvider for PlainTextAuthenticator { - async fn start_authentication_session( - &self, - _authenticator_name: &str, - ) -> Result<(Option>, Box), AuthError> { - let mut response = BytesMut::new(); - let username_as_bytes = self.username.as_bytes(); - let password_as_bytes = self.password.as_bytes(); + fn start_authentication_session<'a>( + &'a self, + _authenticator_name: &'a str, + ) -> BoxedFuture<'_, Result> { + Box::pin(async move { + let mut response = BytesMut::new(); + let username_as_bytes = self.username.as_bytes(); + let password_as_bytes = self.password.as_bytes(); - response.put_u8(0); - response.put_slice(username_as_bytes); - response.put_u8(0); - response.put_slice(password_as_bytes); + response.put_u8(0); + response.put_slice(username_as_bytes); + response.put_u8(0); + response.put_slice(password_as_bytes); - Ok(( - Some(response.to_vec()), - Box::new(PlainTextAuthenticatorSession), - )) + Ok(( + Some(response.to_vec()), + Box::new(PlainTextAuthenticatorSession) as Box, + )) + }) } } diff --git a/scylla/src/lib.rs b/scylla/src/lib.rs index 381fad34d3..785393fa49 100644 --- a/scylla/src/lib.rs +++ b/scylla/src/lib.rs @@ -122,6 +122,8 @@ pub(crate) mod utils; #[doc(hidden)] pub use utils::test_utils; +pub use utils::futures::BoxedFuture; + pub use statement::batch; pub use statement::prepared_statement; pub use statement::query; diff --git a/scylla/src/transport/authenticate_test.rs b/scylla/src/transport/authenticate_test.rs index f781cd552f..9a291e5e33 100644 --- a/scylla/src/transport/authenticate_test.rs +++ b/scylla/src/transport/authenticate_test.rs @@ -1,6 +1,8 @@ -use crate::authentication::{AuthError, AuthenticatorProvider, AuthenticatorSession}; +use crate::authentication::{ + AuthError, AuthInitialResponseAndSession, AuthenticatorProvider, AuthenticatorSession, +}; +use crate::utils::futures::BoxedFuture; use crate::utils::test_utils::unique_keyspace_name; -use async_trait::async_trait; use bytes::{BufMut, BytesMut}; use std::sync::Arc; @@ -28,34 +30,40 @@ async fn authenticate_superuser() { struct CustomAuthenticator; -#[async_trait] impl AuthenticatorSession for CustomAuthenticator { - async fn evaluate_challenge( - &mut self, - _token: Option<&[u8]>, - ) -> Result>, AuthError> { - Err("Challenges are not expected".to_string()) + fn evaluate_challenge<'a>( + &'a mut self, + _token: Option<&'a [u8]>, + ) -> BoxedFuture<'_, Result>, AuthError>> { + Box::pin(async move { Err("Challenges are not expected".to_string()) }) } - async fn success(&mut self, _token: Option<&[u8]>) -> Result<(), AuthError> { - Ok(()) + fn success<'a>( + &'a mut self, + _token: Option<&'a [u8]>, + ) -> BoxedFuture<'_, Result<(), AuthError>> { + Box::pin(async move { Ok(()) }) } } struct CustomAuthenticatorProvider; -#[async_trait] impl AuthenticatorProvider for CustomAuthenticatorProvider { - async fn start_authentication_session( - &self, - _authenticator_name: &str, - ) -> Result<(Option>, Box), AuthError> { - let mut response = BytesMut::new(); - let cred = "\0cassandra\0cassandra"; - - response.put_slice(cred.as_bytes()); - - Ok((Some(response.to_vec()), Box::new(CustomAuthenticator))) + fn start_authentication_session<'a>( + &'a self, + _authenticator_name: &'a str, + ) -> BoxedFuture<'_, Result> { + Box::pin(async move { + let mut response = BytesMut::new(); + let cred = "\0cassandra\0cassandra"; + + response.put_slice(cred.as_bytes()); + + Ok(( + Some(response.to_vec()), + Box::new(CustomAuthenticator) as Box, + )) + }) } } diff --git a/scylla/src/transport/session.rs b/scylla/src/transport/session.rs index f4f5ab2365..0bb8e349c1 100644 --- a/scylla/src/transport/session.rs +++ b/scylla/src/transport/session.rs @@ -7,9 +7,9 @@ use crate::cloud::CloudConfig; use crate::history; use crate::history::HistoryListener; +use crate::utils::futures::BoxedFuture; use crate::utils::pretty::{CommaSeparatedDisplayer, CqlValueDisplayer}; use arc_swap::ArcSwapOption; -use async_trait::async_trait; use bytes::Bytes; use futures::future::join_all; use futures::future::try_join_all; @@ -94,44 +94,45 @@ use scylla_cql::errors::BadQuery; /// Please note that the "known nodes" addresses provided while creating the [`Session`] /// instance are not translated, only IP address retrieved from or sent by Cassandra nodes /// to the driver are. -#[async_trait] pub trait AddressTranslator: Send + Sync { - async fn translate_address( - &self, - untranslated_peer: &UntranslatedPeer, - ) -> Result; + fn translate_address<'a>( + &'a self, + untranslated_peer: &'a UntranslatedPeer, + ) -> BoxedFuture<'_, Result>; } -#[async_trait] impl AddressTranslator for HashMap { - async fn translate_address( - &self, - untranslated_peer: &UntranslatedPeer, - ) -> Result { - match self.get(&untranslated_peer.untranslated_address) { - Some(&translated_addr) => Ok(translated_addr), - None => Err(TranslationError::NoRuleForAddress), - } + fn translate_address<'a>( + &'a self, + untranslated_peer: &'a UntranslatedPeer, + ) -> BoxedFuture<'_, Result> { + Box::pin(async move { + match self.get(&untranslated_peer.untranslated_address) { + Some(&translated_addr) => Ok(translated_addr), + None => Err(TranslationError::NoRuleForAddress), + } + }) } } -#[async_trait] // Notice: this is inefficient, but what else can we do with such poor representation as str? // After all, the cluster size is small enough to make this irrelevant. impl AddressTranslator for HashMap<&'static str, &'static str> { - async fn translate_address( - &self, - untranslated_peer: &UntranslatedPeer, - ) -> Result { - for (&rule_addr_str, &translated_addr_str) in self.iter() { - if let Ok(rule_addr) = SocketAddr::from_str(rule_addr_str) { - if rule_addr == untranslated_peer.untranslated_address { - return SocketAddr::from_str(translated_addr_str) - .map_err(|_| TranslationError::InvalidAddressInRule); + fn translate_address<'a>( + &'a self, + untranslated_peer: &'a UntranslatedPeer, + ) -> BoxedFuture<'_, Result> { + Box::pin(async move { + for (&rule_addr_str, &translated_addr_str) in self.iter() { + if let Ok(rule_addr) = SocketAddr::from_str(rule_addr_str) { + if rule_addr == untranslated_peer.untranslated_address { + return SocketAddr::from_str(translated_addr_str) + .map_err(|_| TranslationError::InvalidAddressInRule); + } } } - } - Err(TranslationError::NoRuleForAddress) + Err(TranslationError::NoRuleForAddress) + }) } } diff --git a/scylla/src/transport/session_builder.rs b/scylla/src/transport/session_builder.rs index 09ee03b961..151e96f95c 100644 --- a/scylla/src/transport/session_builder.rs +++ b/scylla/src/transport/session_builder.rs @@ -197,31 +197,44 @@ impl GenericSessionBuilder { /// # Example /// ``` /// # use std::sync::Arc; + /// # use std::pin::Pin; + /// # use std::future::Future; /// use bytes::Bytes; /// use scylla::{Session, SessionBuilder}; - /// use async_trait::async_trait; /// use scylla::authentication::{AuthenticatorProvider, AuthenticatorSession, AuthError}; /// # use scylla::transport::Compression; /// /// struct CustomAuthenticator; /// - /// #[async_trait] /// impl AuthenticatorSession for CustomAuthenticator { - /// async fn evaluate_challenge(&mut self, token: Option<&[u8]>) -> Result>, AuthError> { - /// Ok(None) + /// fn evaluate_challenge<'a>( + /// &'a mut self, + /// token: Option<&'a [u8]>, + /// ) -> Pin>, AuthError>> + Send + 'a>> { + /// Box::pin(async move { Ok(None) }) /// } /// - /// async fn success(&mut self, token: Option<&[u8]>) -> Result<(), AuthError> { - /// Ok(()) + /// fn success<'a>( + /// &'a mut self, + /// token: Option<&'a [u8]> + /// ) -> Pin> + Send + 'a>> { + /// Box::pin(async move { Ok(()) }) /// } /// } /// /// struct CustomAuthenticatorProvider; /// - /// #[async_trait] /// impl AuthenticatorProvider for CustomAuthenticatorProvider { - /// async fn start_authentication_session(&self, _authenticator_name: &str) -> Result<(Option>, Box), AuthError> { - /// Ok((None, Box::new(CustomAuthenticator))) + /// fn start_authentication_session<'a>( + /// &'a self, + /// authenticator_name: &'a str, + /// ) -> Pin>, Box), AuthError>> + Send + 'a>> { + /// Box::pin(async move { + /// Ok(( + /// None, + /// Box::new(CustomAuthenticator) as Box + /// )) + /// }) /// } /// } /// @@ -249,7 +262,8 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use async_trait::async_trait; + /// # use std::pin::Pin; + /// # use std::future::Future; /// # use std::net::SocketAddr; /// # use std::sync::Arc; /// # use scylla::{Session, SessionBuilder}; @@ -257,13 +271,12 @@ impl GenericSessionBuilder { /// # use scylla::transport::topology::UntranslatedPeer; /// struct IdentityTranslator; /// - /// #[async_trait] /// impl AddressTranslator for IdentityTranslator { - /// async fn translate_address( - /// &self, - /// untranslated_peer: &UntranslatedPeer - /// ) -> Result { - /// Ok(untranslated_peer.untranslated_address) + /// fn translate_address<'a>( + /// &'a self, + /// untranslated_peer: &'a UntranslatedPeer + /// ) -> Pin> + Send + 'a>> { + /// Box::pin(async move { Ok(untranslated_peer.untranslated_address) }) /// } /// } /// @@ -767,7 +780,6 @@ impl GenericSessionBuilder { /// /// # Example /// ``` - /// # use async_trait::async_trait; /// # use std::net::SocketAddr; /// # use std::sync::Arc; /// # use scylla::{Session, SessionBuilder}; diff --git a/scylla/src/utils/futures.rs b/scylla/src/utils/futures.rs new file mode 100644 index 0000000000..4322fa2406 --- /dev/null +++ b/scylla/src/utils/futures.rs @@ -0,0 +1,4 @@ +use std::future::Future; +use std::pin::Pin; + +pub type BoxedFuture<'a, T> = Pin + Send + 'a>>; diff --git a/scylla/src/utils/mod.rs b/scylla/src/utils/mod.rs index c83adbf7e7..04e0b37173 100644 --- a/scylla/src/utils/mod.rs +++ b/scylla/src/utils/mod.rs @@ -1,4 +1,4 @@ +pub(crate) mod futures; pub(crate) mod parse; - pub(crate) mod pretty; pub mod test_utils;