diff --git a/Cargo.toml b/Cargo.toml index c66ba1fc..e94e6a7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,6 +7,7 @@ authors = ["The TiKV Project Authors"] repository = "https://github.com/tikv/client-rust" description = "The Rust language implementation of TiKV client." edition = "2021" +rust-version = "1.93.0" [features] default = ["prometheus"] diff --git a/examples/raw.rs b/examples/raw.rs index cb3bdcd8..8ba5bf06 100644 --- a/examples/raw.rs +++ b/examples/raw.rs @@ -1,6 +1,7 @@ // Copyright 2018 TiKV Project Authors. Licensed under Apache-2.0. #![type_length_limit = "8165158"] +#![allow(clippy::result_large_err)] mod common; diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f06204d1..0e152a80 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.84.1" +channel = "1.93.0" components = ["rustfmt", "clippy"] diff --git a/src/common/errors.rs b/src/common/errors.rs index c48a2665..3e4a5280 100644 --- a/src/common/errors.rs +++ b/src/common/errors.rs @@ -68,7 +68,7 @@ pub enum Error { /// Wraps a `reqwest::Error`. /// Wraps a `grpcio::Error`. #[error("gRPC api error: {0}")] - GrpcAPI(#[from] tonic::Status), + GrpcAPI(tonic::Status), /// Wraps a `grpcio::Error`. #[error("url error: {0}")] Url(#[from] tonic::codegen::http::uri::InvalidUri), @@ -142,6 +142,12 @@ impl From for Error { } } +impl From for Error { + fn from(status: tonic::Status) -> Error { + Error::GrpcAPI(status) + } +} + /// A result holding an [`Error`](enum@Error). pub type Result = result::Result; @@ -157,3 +163,62 @@ macro_rules! internal_err { internal_err!(format!($f, $($arg),+)) }); } + +#[cfg(test)] +mod test { + use tonic::Code; + + use super::Error; + use super::ProtoKeyError; + use super::ProtoRegionError; + + #[test] + fn from_tonic_status_produces_grpc_api_error() { + let status = tonic::Status::new(Code::Unavailable, "network unavailable"); + let error: Error = status.clone().into(); + + let Error::GrpcAPI(actual_status) = error else { + panic!("expected Error::GrpcAPI"); + }; + assert_eq!(actual_status.code(), status.code()); + assert_eq!(actual_status.message(), status.message()); + } + + #[test] + fn grpc_api_variant_accepts_tonic_status_payload() { + let error = Error::GrpcAPI(tonic::Status::new(Code::DeadlineExceeded, "timeout")); + let Error::GrpcAPI(status) = error else { + panic!("expected Error::GrpcAPI"); + }; + assert_eq!(status.code(), Code::DeadlineExceeded); + assert_eq!(status.message(), "timeout"); + } + + #[test] + fn from_proto_region_error_wraps_region_error() { + let region_error = ProtoRegionError { + message: "region stale".to_owned(), + ..Default::default() + }; + let error: Error = region_error.clone().into(); + + let Error::RegionError(actual_region_error) = error else { + panic!("expected Error::RegionError"); + }; + assert_eq!(actual_region_error.message, region_error.message); + } + + #[test] + fn from_proto_key_error_wraps_key_error() { + let key_error = ProtoKeyError { + retryable: "retry later".to_owned(), + ..Default::default() + }; + let error: Error = key_error.clone().into(); + + let Error::KeyError(actual_key_error) = error else { + panic!("expected Error::KeyError"); + }; + assert_eq!(actual_key_error.retryable, key_error.retryable); + } +} diff --git a/src/lib.rs b/src/lib.rs index 85cd9d27..dfb61608 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -91,6 +91,7 @@ //! ``` #![allow(clippy::field_reassign_with_default)] +#![allow(clippy::result_large_err)] pub mod backoff; #[doc(hidden)] diff --git a/src/pd/retry.rs b/src/pd/retry.rs index c9ccf1e1..5449c108 100644 --- a/src/pd/retry.rs +++ b/src/pd/retry.rs @@ -184,7 +184,7 @@ impl RetryClientTrait for RetryClient { cluster .get_all_stores(self.timeout) .await - .map(|resp| resp.stores.into_iter().map(Into::into).collect()) + .map(|resp| resp.stores) }) } diff --git a/src/proto.rs b/src/proto.rs index c86a819a..f0dee9af 100644 --- a/src/proto.rs +++ b/src/proto.rs @@ -5,7 +5,10 @@ pub use protos::*; +// Rust 1.93's clippy::all flags many protobuf-generated wire types as dead code. +// Prior toolchain (1.84.1) did not fail on these generated definitions. #[allow(clippy::doc_lazy_continuation)] +#[allow(dead_code)] mod protos { include!("generated/mod.rs"); } diff --git a/src/store/request.rs b/src/store/request.rs index 65911dcc..2d9c29ad 100644 --- a/src/store/request.rs +++ b/src/store/request.rs @@ -42,7 +42,7 @@ macro_rules! impl_request { .$fun(req) .await .map(|r| Box::new(r.into_inner()) as Box) - .map_err(Error::GrpcAPI) + .map_err(Error::from) } fn label(&self) -> &'static str { diff --git a/src/transaction/requests.rs b/src/transaction/requests.rs index f5859ba0..db524f16 100644 --- a/src/transaction/requests.rs +++ b/src/transaction/requests.rs @@ -241,9 +241,8 @@ pub fn new_pessimistic_prewrite_request( let len = mutations.len(); let mut req = new_prewrite_request(mutations, primary_lock, start_version, lock_ttl); req.for_update_ts = for_update_ts; - req.pessimistic_actions = iter::repeat(PessimisticAction::DoPessimisticCheck.into()) - .take(len) - .collect(); + req.pessimistic_actions = + iter::repeat_n(PessimisticAction::DoPessimisticCheck.into(), len).collect(); req } @@ -343,7 +342,7 @@ impl Shardable for kvrpcpb::CommitRequest { } fn apply_shard(&mut self, shard: Self::Shard) { - self.keys = shard.into_iter().map(Into::into).collect(); + self.keys = shard; } fn apply_store(&mut self, store: &RegionStore) -> Result<()> { @@ -570,7 +569,7 @@ impl Merge for Collect { fn merge(&self, input: Vec>) -> Result { input .into_iter() - .flat_map_ok(|mut resp| resp.take_locks().into_iter().map(Into::into)) + .flat_map_ok(|mut resp| resp.take_locks().into_iter()) .collect() } } diff --git a/src/transaction/transaction.rs b/src/transaction/transaction.rs index ed8eb911..8edb0b4f 100644 --- a/src/transaction/transaction.rs +++ b/src/transaction/transaction.rs @@ -283,9 +283,7 @@ impl Transaction { .retry_multi_region(retry_options.region_backoff) .merge(Collect) .plan(); - plan.execute() - .await - .map(|r| r.into_iter().map(Into::into).collect()) + plan.execute().await.map(|r| r.into_iter().collect()) }) .await .map(move |pairs| pairs.map(move |pair| pair.truncate_keyspace(keyspace))) @@ -806,9 +804,7 @@ impl Transaction { .retry_multi_region(retry_options.region_backoff) .merge(Collect) .plan(); - plan.execute() - .await - .map(|r| r.into_iter().map(Into::into).collect()) + plan.execute().await.map(|r| r.into_iter().collect()) }, ) .await diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 10dc4d3f..3c37c2c4 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -861,7 +861,7 @@ async fn raw_write_million() -> Result<()> { // test batch_scan for batch_num in 1..4 { let _ = client - .batch_scan(iter::repeat(vec![]..).take(batch_num), limit) + .batch_scan(iter::repeat_n(vec![].., batch_num), limit) .await?; // FIXME: `each_limit` parameter does no work as expected. It limits the // entries on each region of each rangqe, instead of each range.