From 6cde00073fb24046298885679855e62acec14b56 Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Sun, 25 Jan 2026 23:42:18 +0100 Subject: [PATCH 1/8] chore: enable workspace configuration of lints in Cargo.toml and use workspace configuration in each package. This allow to customize clippy and rust lint configuration for project. No particular configuration in this commit. --- Cargo.toml | 3 +++ src/api/admin/Cargo.toml | 3 +++ src/api/common/Cargo.toml | 3 +++ src/api/k2v/Cargo.toml | 3 +++ src/api/s3/Cargo.toml | 3 +++ src/block/Cargo.toml | 3 +++ src/db/Cargo.toml | 3 +++ src/garage/Cargo.toml | 3 +++ src/k2v-client/Cargo.toml | 3 +++ src/model/Cargo.toml | 3 +++ src/net/Cargo.toml | 3 +++ src/rpc/Cargo.toml | 3 +++ src/table/Cargo.toml | 3 +++ src/util/Cargo.toml | 3 +++ src/web/Cargo.toml | 3 +++ 15 files changed, 45 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index be2e95a8..aba0b354 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -179,3 +179,6 @@ lto = "thin" codegen-units = 16 opt-level = 3 strip = "debuginfo" + +[workspace.lints.clippy] +# custom configuration diff --git a/src/api/admin/Cargo.toml b/src/api/admin/Cargo.toml index c8bc3423..4d46509a 100644 --- a/src/api/admin/Cargo.toml +++ b/src/api/admin/Cargo.toml @@ -48,3 +48,6 @@ prometheus = { workspace = true, optional = true } [features] metrics = ["opentelemetry-prometheus", "prometheus"] k2v = ["garage_model/k2v"] + +[lints] +workspace = true diff --git a/src/api/common/Cargo.toml b/src/api/common/Cargo.toml index ba38c63b..dba58202 100644 --- a/src/api/common/Cargo.toml +++ b/src/api/common/Cargo.toml @@ -45,3 +45,6 @@ serde.workspace = true serde_json.workspace = true opentelemetry.workspace = true + +[lints] +workspace = true diff --git a/src/api/k2v/Cargo.toml b/src/api/k2v/Cargo.toml index d99c3411..2d417a7e 100644 --- a/src/api/k2v/Cargo.toml +++ b/src/api/k2v/Cargo.toml @@ -35,3 +35,6 @@ serde.workspace = true serde_json.workspace = true opentelemetry.workspace = true + +[lints] +workspace = true diff --git a/src/api/s3/Cargo.toml b/src/api/s3/Cargo.toml index e12df677..620c8c4a 100644 --- a/src/api/s3/Cargo.toml +++ b/src/api/s3/Cargo.toml @@ -58,3 +58,6 @@ serde_json.workspace = true quick-xml.workspace = true opentelemetry.workspace = true + +[lints] +workspace = true diff --git a/src/block/Cargo.toml b/src/block/Cargo.toml index b45898a2..a37ac825 100644 --- a/src/block/Cargo.toml +++ b/src/block/Cargo.toml @@ -40,3 +40,6 @@ tokio-util.workspace = true [features] system-libs = ["zstd/pkg-config"] + +[lints] +workspace = true diff --git a/src/db/Cargo.toml b/src/db/Cargo.toml index 40134169..7e431286 100644 --- a/src/db/Cargo.toml +++ b/src/db/Cargo.toml @@ -33,3 +33,6 @@ bundled-libs = ["rusqlite?/bundled"] lmdb = ["heed"] fjall = ["dep:fjall", "dep:parking_lot"] sqlite = ["rusqlite", "r2d2", "r2d2_sqlite"] + +[lints] +workspace = true diff --git a/src/garage/Cargo.toml b/src/garage/Cargo.toml index 8b726a86..9175ec6b 100644 --- a/src/garage/Cargo.toml +++ b/src/garage/Cargo.toml @@ -119,3 +119,6 @@ system-libs = [ "garage_rpc/system-libs", "sodiumoxide/use-pkg-config", ] + +[lints] +workspace = true diff --git a/src/k2v-client/Cargo.toml b/src/k2v-client/Cargo.toml index ccbc7aa3..3c1076c0 100644 --- a/src/k2v-client/Cargo.toml +++ b/src/k2v-client/Cargo.toml @@ -45,3 +45,6 @@ path = "lib.rs" name = "k2v-cli" path = "bin/k2v-cli.rs" required-features = ["cli"] + +[lints] +workspace = true diff --git a/src/model/Cargo.toml b/src/model/Cargo.toml index 0f8d040c..80c2f61e 100644 --- a/src/model/Cargo.toml +++ b/src/model/Cargo.toml @@ -46,3 +46,6 @@ k2v = ["garage_util/k2v"] lmdb = ["garage_db/lmdb"] sqlite = ["garage_db/sqlite"] fjall = ["garage_db/fjall"] + +[lints] +workspace = true diff --git a/src/net/Cargo.toml b/src/net/Cargo.toml index 0d146ae1..314f748a 100644 --- a/src/net/Cargo.toml +++ b/src/net/Cargo.toml @@ -42,3 +42,6 @@ opentelemetry-contrib = { workspace = true, optional = true } [dev-dependencies] pretty_env_logger.workspace = true + +[lints] +workspace = true diff --git a/src/rpc/Cargo.toml b/src/rpc/Cargo.toml index 1c35dcd9..4f030540 100644 --- a/src/rpc/Cargo.toml +++ b/src/rpc/Cargo.toml @@ -51,3 +51,6 @@ opentelemetry.workspace = true kubernetes-discovery = ["kube", "k8s-openapi", "schemars"] consul-discovery = ["reqwest", "thiserror"] system-libs = ["sodiumoxide/use-pkg-config"] + +[lints] +workspace = true diff --git a/src/table/Cargo.toml b/src/table/Cargo.toml index 3495380f..7739f18f 100644 --- a/src/table/Cargo.toml +++ b/src/table/Cargo.toml @@ -33,3 +33,6 @@ serde_bytes.workspace = true futures.workspace = true futures-util.workspace = true tokio.workspace = true + +[lints] +workspace = true diff --git a/src/util/Cargo.toml b/src/util/Cargo.toml index 48d39872..a2478119 100644 --- a/src/util/Cargo.toml +++ b/src/util/Cargo.toml @@ -52,3 +52,6 @@ mktemp.workspace = true [features] k2v = [] + +[lints] +workspace = true diff --git a/src/web/Cargo.toml b/src/web/Cargo.toml index ba0ecc04..e21ff4ab 100644 --- a/src/web/Cargo.toml +++ b/src/web/Cargo.toml @@ -31,3 +31,6 @@ hyper.workspace = true tokio.workspace = true opentelemetry.workspace = true + +[lints] +workspace = true From 08fd6e659f8a3c76d459446cbdc35e599a862924 Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Sun, 25 Jan 2026 23:46:05 +0100 Subject: [PATCH 2/8] docs: add missing backticks in documentation this improve readability of documentation. enable associated clippy lint `doc_markdown` --- Cargo.toml | 3 ++- src/api/admin/router_v0.rs | 2 +- src/api/admin/router_v1.rs | 2 +- src/api/admin/router_v2.rs | 2 +- src/api/common/common_error.rs | 8 ++++---- src/api/k2v/item.rs | 4 ++-- src/api/k2v/range.rs | 2 +- src/api/k2v/router.rs | 2 +- src/api/s3/error.rs | 4 ++-- src/api/s3/list.rs | 2 +- src/api/s3/router.rs | 2 +- src/block/layout.rs | 2 +- src/block/metrics.rs | 2 +- src/block/rc.rs | 6 +++--- src/garage/cli/local/convert_db.rs | 2 +- src/garage/cli/structs.rs | 16 +++++++-------- src/garage/secrets.rs | 12 +++++------ src/garage/tests/common/mod.rs | 2 +- src/k2v-client/lib.rs | 32 +++++++++++++++--------------- src/model/admin_token_table.rs | 2 +- src/model/bucket_table.rs | 6 +++--- src/model/helper/bucket.rs | 4 ++-- src/model/helper/locked.rs | 8 ++++---- src/model/k2v/causality.rs | 4 ++-- src/model/k2v/item_table.rs | 4 ++-- src/model/k2v/seen.rs | 2 +- src/model/key_table.rs | 4 ++-- src/model/s3/mpu_table.rs | 8 ++++---- src/model/s3/object_table.rs | 18 ++++++++--------- src/model/snapshot.rs | 2 +- src/net/bytes_buf.rs | 10 +++++----- src/net/message.rs | 10 +++++----- src/net/netapp.rs | 16 +++++++-------- src/net/peering.rs | 2 +- src/net/recv.rs | 4 ++-- src/net/send.rs | 4 ++-- src/net/stream.rs | 10 +++++----- src/net/util.rs | 4 ++-- src/rpc/layout/graph_algo.rs | 12 +++++------ src/rpc/layout/helper.rs | 2 +- src/rpc/layout/mod.rs | 18 ++++++++--------- src/rpc/layout/version.rs | 14 ++++++------- src/rpc/metrics.rs | 2 +- src/rpc/rpc_helper.rs | 8 ++++---- src/rpc/system.rs | 8 ++++---- src/rpc/system_metrics.rs | 2 +- src/table/gc.rs | 10 +++++----- src/table/metrics.rs | 2 +- src/table/schema.rs | 2 +- src/util/background/mod.rs | 4 ++-- src/util/background/worker.rs | 4 ++-- src/util/config.rs | 8 ++++---- src/util/crdt/crdt.rs | 8 ++++---- src/util/crdt/lww_map.rs | 2 +- src/util/data.rs | 2 +- src/util/encode.rs | 8 ++++---- src/util/error.rs | 2 +- src/util/migrate.rs | 2 +- 58 files changed, 175 insertions(+), 174 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aba0b354..6d701055 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -181,4 +181,5 @@ opt-level = 3 strip = "debuginfo" [workspace.lints.clippy] -# custom configuration +# pedantic lints configuration +doc_markdown = "warn" diff --git a/src/api/admin/router_v0.rs b/src/api/admin/router_v0.rs index 9dd742ba..168c21d3 100644 --- a/src/api/admin/router_v0.rs +++ b/src/api/admin/router_v0.rs @@ -77,7 +77,7 @@ pub enum Endpoint { impl Endpoint { /// Determine which S3 endpoint a request is for using the request, and a bucket which was /// possibly extracted from the Host header. - /// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets + /// Returns Self plus bucket name, if endpoint is not `Endpoint::ListBuckets` pub fn from_request(req: &Request) -> Result { let uri = req.uri(); let path = uri.path(); diff --git a/src/api/admin/router_v1.rs b/src/api/admin/router_v1.rs index 138a801d..2fdb996d 100644 --- a/src/api/admin/router_v1.rs +++ b/src/api/admin/router_v1.rs @@ -79,7 +79,7 @@ pub enum Endpoint { impl Endpoint { /// Determine which S3 endpoint a request is for using the request, and a bucket which was /// possibly extracted from the Host header. - /// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets + /// Returns Self plus bucket name, if endpoint is not `Endpoint::ListBuckets` pub fn from_request(req: &Request) -> Result { let uri = req.uri(); let path = uri.path(); diff --git a/src/api/admin/router_v2.rs b/src/api/admin/router_v2.rs index 3009d128..7fcce6e7 100644 --- a/src/api/admin/router_v2.rs +++ b/src/api/admin/router_v2.rs @@ -15,7 +15,7 @@ use crate::Authorization; impl AdminApiRequest { /// Determine which S3 endpoint a request is for using the request, and a bucket which was /// possibly extracted from the Host header. - /// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets + /// Returns Self plus bucket name, if endpoint is not `Endpoint::ListBuckets` pub async fn from_request(req: Request) -> Result { let uri = req.uri().clone(); let path = uri.path(); diff --git a/src/api/common/common_error.rs b/src/api/common/common_error.rs index e110b1d6..dddf6f61 100644 --- a/src/api/common/common_error.rs +++ b/src/api/common/common_error.rs @@ -142,10 +142,10 @@ impl TryFrom for CommonError { } } -/// This function converts HelperErrors into CommonErrors, -/// for variants that exist in CommonError. -/// This is used for helper functions that might return InvalidBucketName -/// or NoSuchBucket for instance, and we want to pass that error +/// This function converts `HelperErrors` into `CommonErrors`, +/// for variants that exist in `CommonError`. +/// This is used for helper functions that might return `InvalidBucketName` +/// or `NoSuchBucket` for instance, and we want to pass that error /// up to our caller. pub fn pass_helper_error(err: HelperError) -> CommonError { match CommonError::try_from(err) { diff --git a/src/api/k2v/item.rs b/src/api/k2v/item.rs index 0fb945d2..2482d7cd 100644 --- a/src/api/k2v/item.rs +++ b/src/api/k2v/item.rs @@ -97,7 +97,7 @@ impl ReturnFormat { } } -/// Handle ReadItem request +/// Handle `ReadItem` request #[allow(clippy::ptr_arg)] pub async fn handle_read_item( ctx: ReqCtx, @@ -201,7 +201,7 @@ pub async fn handle_delete_item( .body(empty_body())?) } -/// Handle ReadItem request +/// Handle `ReadItem` request #[allow(clippy::ptr_arg)] pub async fn handle_poll_item( ctx: ReqCtx, diff --git a/src/api/k2v/range.rs b/src/api/k2v/range.rs index eb4738db..dc1bdaac 100644 --- a/src/api/k2v/range.rs +++ b/src/api/k2v/range.rs @@ -1,6 +1,6 @@ //! Utility module for retrieving ranges of items in Garage tables //! Implements parameters (prefix, start, end, limit) as specified -//! for endpoints ReadIndex, ReadBatch and DeleteBatch +//! for endpoints `ReadIndex`, `ReadBatch` and `DeleteBatch` use std::sync::Arc; diff --git a/src/api/k2v/router.rs b/src/api/k2v/router.rs index a04b0f81..241bb9d2 100644 --- a/src/api/k2v/router.rs +++ b/src/api/k2v/router.rs @@ -53,7 +53,7 @@ pub enum Endpoint { impl Endpoint { /// Determine which S3 endpoint a request is for using the request, and a bucket which was /// possibly extracted from the Host header. - /// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets + /// Returns Self plus bucket name, if endpoint is not `Endpoint::ListBuckets` pub fn from_request(req: &Request) -> Result<(Self, String), Error> { let uri = req.uri(); let path = uri.path().trim_start_matches('/'); diff --git a/src/api/s3/error.rs b/src/api/s3/error.rs index f36078f3..58badf21 100644 --- a/src/api/s3/error.rs +++ b/src/api/s3/error.rs @@ -50,11 +50,11 @@ pub enum Error { #[error("Parts given to CompleteMultipartUpload do not match uploaded parts")] InvalidPart, - /// Parts given to CompleteMultipartUpload were not in ascending order + /// Parts given to `CompleteMultipartUpload` were not in ascending order #[error("Parts given to CompleteMultipartUpload were not in ascending order")] InvalidPartOrder, - /// In CompleteMultipartUpload: not enough data + /// In `CompleteMultipartUpload`: not enough data /// (here we are more lenient than AWS S3) #[error("Proposed upload is smaller than the minimum allowed object size")] EntityTooSmall, diff --git a/src/api/s3/list.rs b/src/api/s3/list.rs index 58b66388..f306a1e5 100644 --- a/src/api/s3/list.rs +++ b/src/api/s3/list.rs @@ -939,7 +939,7 @@ fn common_prefix<'a>(object: &'a Object, query: &ListQueryCommon) -> Option<&'a } } -/// URIencode a value if needed +/// `URIencode` a value if needed fn uriencode_maybe(s: &str, yes: bool) -> s3_xml::Value { if yes { s3_xml::Value(uri_encode(s, true)) diff --git a/src/api/s3/router.rs b/src/api/s3/router.rs index 30af6895..ca01c3cd 100644 --- a/src/api/s3/router.rs +++ b/src/api/s3/router.rs @@ -309,7 +309,7 @@ pub enum Endpoint { impl Endpoint { /// Determine which S3 endpoint a request is for using the request, and a bucket which was /// possibly extracted from the Host header. - /// Returns Self plus bucket name, if endpoint is not Endpoint::ListBuckets + /// Returns Self plus bucket name, if endpoint is not `Endpoint::ListBuckets` pub fn from_request( req: &Request, bucket: Option, diff --git a/src/block/layout.rs b/src/block/layout.rs index 7e818d77..918b556e 100644 --- a/src/block/layout.rs +++ b/src/block/layout.rs @@ -21,7 +21,7 @@ pub(crate) struct DataLayout { pub(crate) data_dirs: Vec, markers: HashMap, - /// Primary storage location (index in data_dirs) for each partition + /// Primary storage location (index in `data_dirs`) for each partition /// = the location where the data is supposed to be, blocks are always /// written there (copies in other dirs may be deleted if they exist) pub(crate) part_prim: Vec, diff --git a/src/block/metrics.rs b/src/block/metrics.rs index 81021fe1..ffed7d1d 100644 --- a/src/block/metrics.rs +++ b/src/block/metrics.rs @@ -6,7 +6,7 @@ use opentelemetry::{global, metrics::*}; use garage_db as db; -/// TableMetrics reference all counter used for metrics +/// `TableMetrics` reference all counter used for metrics pub struct BlockManagerMetrics { pub(crate) _compression_level: ValueObserver, pub(crate) _rc_size: ValueObserver, diff --git a/src/block/rc.rs b/src/block/rc.rs index d8b611ed..24f67cf2 100644 --- a/src/block/rc.rs +++ b/src/block/rc.rs @@ -136,14 +136,14 @@ impl BlockRc { pub(crate) enum RcEntry { /// Present: the block has `count` references, with `count` > 0. /// - /// This is stored as u64::to_be_bytes(count) + /// This is stored as `u64::to_be_bytes(count)` Present { count: u64 }, /// Deletable: the block has zero references, and can be deleted - /// once time (returned by now_msec) is larger than at_time + /// once time (returned by `now_msec`) is larger than `at_time` /// (in millis since Unix epoch) /// - /// This is stored as [0u8; 8] followed by u64::to_be_bytes(at_time), + /// This is stored as [0u8; 8] followed by `u64::to_be_bytes(at_time)`, /// (this allows for the data format to be backwards compatible with /// previous Garage versions that didn't have this intermediate state) Deletable { at_time: u64 }, diff --git a/src/garage/cli/local/convert_db.rs b/src/garage/cli/local/convert_db.rs index 6ac34ee0..e1a67d02 100644 --- a/src/garage/cli/local/convert_db.rs +++ b/src/garage/cli/local/convert_db.rs @@ -7,7 +7,7 @@ use garage_db::*; /// K2V command line interface #[derive(StructOpt, Debug)] pub struct ConvertDbOpt { - /// Input database path (not the same as metadata_dir, see + /// Input database path (not the same as `metadata_dir`, see /// #[structopt(short = "i")] input_path: PathBuf, diff --git a/src/garage/cli/structs.rs b/src/garage/cli/structs.rs index 9073991d..e7422721 100644 --- a/src/garage/cli/structs.rs +++ b/src/garage/cli/structs.rs @@ -71,7 +71,7 @@ pub enum Command { /// The result is printed to `stdout` in JSON format. #[structopt(name = "json-api", version = garage_version())] JsonApi { - /// The admin API endpoint to invoke, e.g. GetClusterStatus + /// The admin API endpoint to invoke, e.g. `GetClusterStatus` endpoint: String, /// The JSON payload, or `-` to read from `stdin` #[structopt(default_value = "null")] @@ -475,7 +475,7 @@ pub struct KeyNewOpt { #[structopt(default_value = "Unnamed key")] pub name: String, /// Set an expiration time for the access key - /// (see docs.rs/parse_duration for date format) + /// (see `docs.rs/parse_duration` for date format) #[structopt(long = "expires-in")] pub expires_in: Option, } @@ -486,7 +486,7 @@ pub struct KeySetOpt { pub key_pattern: String, /// Set an expiration time for the access key - /// (see docs.rs/parse_duration for date format) + /// (see `docs.rs/parse_duration` for date format) #[structopt(long = "expires-in")] pub expires_in: Option, /// Set the access key to never expire @@ -518,7 +518,7 @@ pub struct KeyPermOpt { /// ID or name of the key pub key_pattern: String, - /// Flag that allows key to create buckets using S3's CreateBucket call + /// Flag that allows key to create buckets using S3's `CreateBucket` call #[structopt(long = "create-bucket")] pub create_bucket: bool, } @@ -597,12 +597,12 @@ pub enum AdminTokenOperation { pub struct AdminTokenCreateOp { /// Set a name for the token pub name: Option, - /// Set an expiration time for the token (see docs.rs/parse_duration for date + /// Set an expiration time for the token (see `docs.rs/parse_duration` for date /// format) #[structopt(long = "expires-in")] pub expires_in: Option, /// Set a limited scope for the token, as a comma-separated list of - /// admin API functions (e.g. GetClusterStatus, etc.). The default scope + /// admin API functions (e.g. `GetClusterStatus`, etc.). The default scope /// is `*`, which allows access to all admin API functions. /// Note that granting a scope that allows `CreateAdminToken` or /// `UpdateAdminToken` allows for privilege escalation, and is therefore @@ -619,7 +619,7 @@ pub struct AdminTokenSetOp { /// Name or prefix of the ID of the token to modify pub api_token: String, - /// Set an expiration time for the token (see docs.rs/parse_duration for date + /// Set an expiration time for the token (see `docs.rs/parse_duration` for date /// format) #[structopt(long = "expires-in")] pub expires_in: Option, @@ -628,7 +628,7 @@ pub struct AdminTokenSetOp { pub never_expires: bool, /// Set a limited scope for the token, as a comma-separated list of - /// admin API functions (e.g. GetClusterStatus, etc.), or `*` to allow + /// admin API functions (e.g. `GetClusterStatus`, etc.), or `*` to allow /// all admin API functions. /// Use `--scope=+Scope1,Scope2` to add scopes to the existing list, /// and `--scope=-Scope1,Scope2` to remove scopes from the existing list. diff --git a/src/garage/secrets.rs b/src/garage/secrets.rs index 17781efe..e89a3b45 100644 --- a/src/garage/secrets.rs +++ b/src/garage/secrets.rs @@ -17,32 +17,32 @@ pub struct Secrets { )] pub allow_world_readable_secrets: Option, - /// RPC secret network key, used to replace rpc_secret in config.toml when running the + /// RPC secret network key, used to replace `rpc_secret` in config.toml when running the /// daemon or doing admin operations #[structopt(short = "s", long = "rpc-secret", env = "GARAGE_RPC_SECRET")] pub rpc_secret: Option, - /// RPC secret network key, used to replace rpc_secret in config.toml and rpc-secret + /// RPC secret network key, used to replace `rpc_secret` in config.toml and rpc-secret /// when running the daemon or doing admin operations #[structopt(long = "rpc-secret-file", env = "GARAGE_RPC_SECRET_FILE")] pub rpc_secret_file: Option, - /// Admin API authentication token, replaces admin.admin_token in config.toml when + /// Admin API authentication token, replaces `admin.admin_token` in config.toml when /// running the Garage daemon #[structopt(long = "admin-token", env = "GARAGE_ADMIN_TOKEN")] pub admin_token: Option, - /// Admin API authentication token file path, replaces admin.admin_token in config.toml + /// Admin API authentication token file path, replaces `admin.admin_token` in config.toml /// and admin-token when running the Garage daemon #[structopt(long = "admin-token-file", env = "GARAGE_ADMIN_TOKEN_FILE")] pub admin_token_file: Option, - /// Metrics API authentication token, replaces admin.metrics_token in config.toml when + /// Metrics API authentication token, replaces `admin.metrics_token` in config.toml when /// running the Garage daemon #[structopt(long = "metrics-token", env = "GARAGE_METRICS_TOKEN")] pub metrics_token: Option, - /// Metrics API authentication token file path, replaces admin.metrics_token in config.toml + /// Metrics API authentication token file path, replaces `admin.metrics_token` in config.toml /// and metrics-token when running the Garage daemon #[structopt(long = "metrics-token-file", env = "GARAGE_METRICS_TOKEN_FILE")] pub metrics_token_file: Option, diff --git a/src/garage/tests/common/mod.rs b/src/garage/tests/common/mod.rs index 1273bad1..a7e08de1 100644 --- a/src/garage/tests/common/mod.rs +++ b/src/garage/tests/common/mod.rs @@ -75,7 +75,7 @@ impl Context { bucket_name } - /// Build a K2vClient for a given bucket + /// Build a `K2vClient` for a given bucket #[cfg(feature = "k2v")] pub fn k2v_client(&self, bucket: &str) -> K2vClient { let config = k2v_client::K2vClientConfig { diff --git a/src/k2v-client/lib.rs b/src/k2v-client/lib.rs index d521422a..42bfa9f6 100644 --- a/src/k2v-client/lib.rs +++ b/src/k2v-client/lib.rs @@ -95,7 +95,7 @@ impl K2vClient { }) } - /// Perform a ReadItem request, reading the value(s) stored for a single pk+sk. + /// Perform a `ReadItem` request, reading the value(s) stored for a single pk+sk. pub async fn read_item( &self, partition_key: &str, @@ -134,7 +134,7 @@ impl K2vClient { } } - /// Perform a PollItem request, waiting for the value(s) stored for a single pk+sk to be + /// Perform a `PollItem` request, waiting for the value(s) stored for a single pk+sk to be /// updated. pub async fn poll_item( &self, @@ -190,7 +190,7 @@ impl K2vClient { } } - /// Perform a PollRange request, waiting for any change in a given range of keys + /// Perform a `PollRange` request, waiting for any change in a given range of keys /// to occur pub async fn poll_range( &self, @@ -239,7 +239,7 @@ impl K2vClient { })) } - /// Perform an InsertItem request, inserting a value for a single pk+sk. + /// Perform an `InsertItem` request, inserting a value for a single pk+sk. pub async fn insert_item( &self, partition_key: &str, @@ -258,7 +258,7 @@ impl K2vClient { Ok(()) } - /// Perform a DeleteItem request, deleting the value(s) stored for a single pk+sk. + /// Perform a `DeleteItem` request, deleting the value(s) stored for a single pk+sk. pub async fn delete_item( &self, partition_key: &str, @@ -274,7 +274,7 @@ impl K2vClient { Ok(()) } - /// Perform a ReadIndex request, listing partition key which have at least one associated + /// Perform a `ReadIndex` request, listing partition key which have at least one associated /// sort key, and which matches the filter. pub async fn read_index( &self, @@ -300,7 +300,7 @@ impl K2vClient { }) } - /// Perform an InsertBatch request, inserting multiple values at once. Note: this operation is + /// Perform an `InsertBatch` request, inserting multiple values at once. Note: this operation is /// *not* atomic: it is possible for some sub-operations to fails and others to success. In /// that case, failure is reported. pub async fn insert_batch(&self, operations: &[BatchInsertOp<'_>]) -> Result<(), Error> { @@ -312,7 +312,7 @@ impl K2vClient { Ok(()) } - /// Perform a ReadBatch request, reading multiple values or range of values at once. + /// Perform a `ReadBatch` request, reading multiple values or range of values at once. pub async fn read_batch( &self, operations: &[BatchReadOp<'_>], @@ -346,7 +346,7 @@ impl K2vClient { .collect()) } - /// Perform a DeleteBatch request, deleting multiple values or range of values at once, without + /// Perform a `DeleteBatch` request, deleting multiple values or range of values at once, without /// providing causality information. pub async fn delete_batch(&self, operations: &[BatchDeleteOp<'_>]) -> Result, Error> { let url = self.build_url(None, &[("delete", "")]); @@ -588,7 +588,7 @@ impl Serialize for K2vValue { } } -/// A set of K2vValue and associated causality information. +/// A set of `K2vValue` and associated causality information. #[derive(Debug, Clone, Serialize)] pub struct CausalValue { pub causality: CausalityToken, @@ -621,12 +621,12 @@ pub struct PollRangeFilter<'a> { pub prefix: Option<&'a str>, } -/// Response to a poll_range query +/// Response to a `poll_range` query #[derive(Debug, Default, Clone, Serialize)] pub struct PollRangeResult { - /// List of items that have changed since last PollRange call. + /// List of items that have changed since last `PollRange` call. pub items: BTreeMap, - /// opaque string representing items already seen for future PollRange calls. + /// opaque string representing items already seen for future `PollRange` calls. pub seen_marker: String, } @@ -696,7 +696,7 @@ pub struct PartitionInfo { pub bytes: u64, } -/// Single sub-operation of an InsertBatch. +/// Single sub-operation of an `InsertBatch`. #[derive(Debug, Clone, Serialize)] pub struct BatchInsertOp<'a> { #[serde(rename = "pk")] @@ -709,7 +709,7 @@ pub struct BatchInsertOp<'a> { pub value: K2vValue, } -/// Single sub-operation of a ReadBatch. +/// Single sub-operation of a `ReadBatch`. #[derive(Debug, Default, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct BatchReadOp<'a> { @@ -743,7 +743,7 @@ struct BatchReadItem { v: Vec, } -/// Single sub-operation of a DeleteBatch +/// Single sub-operation of a `DeleteBatch` #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename_all = "camelCase")] pub struct BatchDeleteOp<'a> { diff --git a/src/model/admin_token_table.rs b/src/model/admin_token_table.rs index 0af8ec78..25c7bd62 100644 --- a/src/model/admin_token_table.rs +++ b/src/model/admin_token_table.rs @@ -73,7 +73,7 @@ impl Crdt for AdminApiTokenScope { impl AdminApiToken { /// Create a new admin API token. - /// Returns the AdminApiToken object, which contains the hashed bearer token, + /// Returns the `AdminApiToken` object, which contains the hashed bearer token, /// as well as the plaintext bearer token. pub fn new(name: &str) -> (Self, String) { use argon2::{ diff --git a/src/model/bucket_table.rs b/src/model/bucket_table.rs index 7317c36f..0b1766b7 100644 --- a/src/model/bucket_table.rs +++ b/src/model/bucket_table.rs @@ -35,7 +35,7 @@ mod v08 { /// Map of aliases that are or have been given to this bucket /// in the global namespace /// (not authoritative: this is just used as an indication to - /// map back to aliases when doing ListBuckets) + /// map back to aliases when doing `ListBuckets`) pub aliases: crdt::LwwMap, /// Map of aliases that are or have been given to this bucket /// in namespaces local to keys @@ -148,7 +148,7 @@ mod v2 { /// Map of aliases that are or have been given to this bucket /// in the global namespace /// (not authoritative: this is just used as an indication to - /// map back to aliases when doing ListBuckets) + /// map back to aliases when doing `ListBuckets`) pub aliases: crdt::LwwMap, /// Map of aliases that are or have been given to this bucket /// in namespaces local to keys @@ -241,7 +241,7 @@ impl AutoCrdt for BucketQuotas { } impl BucketParams { - /// Create an empty BucketParams with no authorized keys and no website access + /// Create an empty `BucketParams` with no authorized keys and no website access fn new() -> Self { BucketParams { creation_date: now_msec(), diff --git a/src/model/helper/bucket.rs b/src/model/helper/bucket.rs index aab13bac..b1caded5 100644 --- a/src/model/helper/bucket.rs +++ b/src/model/helper/bucket.rs @@ -79,7 +79,7 @@ impl<'a> BucketHelper<'a> { /// aliases directly using the data provided in the `api_key` parameter. /// As a consequence, it does not provide read-after-write guarantees. /// - /// In case no such bucket is found, this function returns a NoSuchBucket error. + /// In case no such bucket is found, this function returns a `NoSuchBucket` error. #[allow(clippy::ptr_arg)] pub fn resolve_bucket_fast( &self, @@ -147,7 +147,7 @@ impl<'a> BucketHelper<'a> { /// /// - this function does quorum reads to ensure consistency. /// - this function fetches the Key entry from the key table to ensure up-to-date data - /// - this function returns None if the bucket is not found, instead of HelperError::NoSuchBucket + /// - this function returns None if the bucket is not found, instead of `HelperError::NoSuchBucket` #[allow(clippy::ptr_arg)] pub async fn resolve_bucket( &self, diff --git a/src/model/helper/locked.rs b/src/model/helper/locked.rs index 98344b63..62d8505e 100644 --- a/src/model/helper/locked.rs +++ b/src/model/helper/locked.rs @@ -17,13 +17,13 @@ use crate::helper::key::KeyHelper; use crate::key_table::*; use crate::permission::BucketKeyPerm; -/// A LockedHelper is the mandatory struct to hold when doing operations +/// A `LockedHelper` is the mandatory struct to hold when doing operations /// that modify access keys or bucket aliases. This structure takes /// a lock to a unit value that is in the globally-shared Garage struct. /// /// This avoid several concurrent requests to modify the list of buckets /// and aliases at the same time, ending up in inconsistent states. -/// This DOES NOT FIX THE FUNDAMENTAL ISSUE as CreateBucket requests handled +/// This DOES NOT FIX THE FUNDAMENTAL ISSUE as `CreateBucket` requests handled /// by different API nodes can still break the cluster, but it is a first /// fix that allows consistency to be maintained if all such requests are /// directed to a single node, which is doable for many deployments. @@ -167,7 +167,7 @@ impl<'a> LockedHelper<'a> { } /// Ensures a bucket does not have a certain global alias. - /// Contrarily to unset_global_bucket_alias, this does not + /// Contrarily to `unset_global_bucket_alias`, this does not /// fail on any condition other than: /// - bucket cannot be found (its fine if it is in deleted state) /// - alias cannot be found (its fine if it points to nothing or @@ -335,7 +335,7 @@ impl<'a> LockedHelper<'a> { } /// Ensures a bucket does not have a certain local alias. - /// Contrarily to unset_local_bucket_alias, this does not + /// Contrarily to `unset_local_bucket_alias`, this does not /// fail on any condition other than: /// - bucket cannot be found (its fine if it is in deleted state) /// - key cannot be found (its fine if alias in key points to nothing diff --git a/src/model/k2v/causality.rs b/src/model/k2v/causality.rs index 7d311ede..654932bd 100644 --- a/src/model/k2v/causality.rs +++ b/src/model/k2v/causality.rs @@ -1,9 +1,9 @@ -//! Implements a CausalContext, which is a set of timestamps for each +//! Implements a `CausalContext`, which is a set of timestamps for each //! node -- a vector clock --, indicating that the versions with //! timestamps <= these numbers have been seen and can be //! overwritten by a subsequent write. //! -//! The textual representation of a CausalContext, which we call a +//! The textual representation of a `CausalContext`, which we call a //! "causality token", is used in the API and must be sent along with //! each write or delete operation to indicate the previously seen //! versions that we want to overwrite or delete. diff --git a/src/model/k2v/item_table.rs b/src/model/k2v/item_table.rs index 9e3ba5a5..9378a1d1 100644 --- a/src/model/k2v/item_table.rs +++ b/src/model/k2v/item_table.rs @@ -56,7 +56,7 @@ mod v08 { pub use v08::*; impl K2VItem { - /// Creates a new K2VItem when no previous entry existed in the db + /// Creates a new `K2VItem` when no previous entry existed in the db pub fn new(bucket_id: Uuid, partition_key: String, sort_key: String) -> Self { Self { partition: K2VItemPartition { @@ -67,7 +67,7 @@ impl K2VItem { items: BTreeMap::new(), } } - /// Updates a K2VItem with a new value or a deletion event + /// Updates a `K2VItem` with a new value or a deletion event pub fn update( &mut self, this_node: Uuid, diff --git a/src/model/k2v/seen.rs b/src/model/k2v/seen.rs index 59d4ca5b..ad38c6ae 100644 --- a/src/model/k2v/seen.rs +++ b/src/model/k2v/seen.rs @@ -1,4 +1,4 @@ -//! Implements a RangeSeenMarker, a data type used in the PollRange API +//! Implements a `RangeSeenMarker`, a data type used in the `PollRange` API //! to indicate which items in the range have already been seen //! and which have not been seen yet. //! diff --git a/src/model/key_table.rs b/src/model/key_table.rs index 6eeae171..72ca0182 100644 --- a/src/model/key_table.rs +++ b/src/model/key_table.rs @@ -27,7 +27,7 @@ mod v08 { /// Configuration for a key #[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] pub struct KeyParams { - /// The secret_key associated (immutable) + /// The `secret_key` associated (immutable) pub secret_key: String, /// Name for the key @@ -73,7 +73,7 @@ mod v2 { /// Key's creation date, if known (older versions of Garage didn't keep track /// of this information) pub created: Option, - /// The secret_key associated (immutable) + /// The `secret_key` associated (immutable) pub secret_key: String, /// Name for the key diff --git a/src/model/s3/mpu_table.rs b/src/model/s3/mpu_table.rs index 135e1888..52734d27 100644 --- a/src/model/s3/mpu_table.rs +++ b/src/model/s3/mpu_table.rs @@ -31,12 +31,12 @@ mod v09 { /// The timestamp at which the multipart upload was created pub timestamp: u64, /// Is this multipart upload deleted - /// The MultipartUpload is marked as deleted as soon as the + /// The `MultipartUpload` is marked as deleted as soon as the /// multipart upload is either completed or aborted pub deleted: crdt::Bool, /// List of uploaded parts, key = (part number, timestamp) /// In case of retries, all versions for each part are kept - /// Everything is cleaned up only once the MultipartUpload is marked deleted + /// Everything is cleaned up only once the `MultipartUpload` is marked deleted pub parts: crdt::Map, // Back link to bucket+key so that we can find the object this mpu @@ -58,9 +58,9 @@ mod v09 { /// The version of an uploaded part #[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize)] pub struct MpuPart { - /// Links to a Version in VersionTable + /// Links to a Version in `VersionTable` pub version: Uuid, - /// ETag of the content of this part (known only once done uploading) + /// `ETag` of the content of this part (known only once done uploading) pub etag: Option, /// Checksum requested by x-amz-checksum-algorithm #[serde(default)] diff --git a/src/model/s3/object_table.rs b/src/model/s3/object_table.rs index ebee67f8..aff4bbfd 100644 --- a/src/model/s3/object_table.rs +++ b/src/model/s3/object_table.rs @@ -249,7 +249,7 @@ mod v010 { #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize)] pub enum ObjectVersionEncryption { SseC { - /// Encrypted serialized ObjectVersionInner struct. + /// Encrypted serialized `ObjectVersionInner` struct. /// This is never compressed, just encrypted using AES256-GCM. #[serde(with = "serde_bytes")] inner: Vec, @@ -460,7 +460,7 @@ mod v2 { #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize)] pub enum ObjectVersionEncryption { SseC { - /// Encrypted serialized ObjectVersionInner struct. + /// Encrypted serialized `ObjectVersionInner` struct. /// This is never compressed, just encrypted using AES256-GCM. #[serde(with = "serde_bytes")] inner: Vec, @@ -480,7 +480,7 @@ mod v2 { } /// Vector of headers, as tuples of the format (header name, header value) - /// Note: checksum can be Some(_) with checksum_type = None for objects that + /// Note: checksum can be Some(_) with `checksum_type` = None for objects that /// have been migrated from Garage version before v2.0, as the distinction between /// full-object and composite checksums was not implemented yet. #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug, Serialize, Deserialize)] @@ -665,9 +665,9 @@ impl ObjectVersion { /// Is the object version currently being uploaded /// - /// matches only multipart uploads if check_multipart is Some(true) - /// matches only non-multipart uploads if check_multipart is Some(false) - /// matches both if check_multipart is None + /// matches only multipart uploads if `check_multipart` is Some(true) + /// matches only non-multipart uploads if `check_multipart` is Some(false) + /// matches both if `check_multipart` is None pub fn is_uploading(&self, check_multipart: Option) -> bool { match &self.state { ObjectVersionState::Uploading { multipart, .. } => { @@ -763,9 +763,9 @@ pub enum ObjectFilter { IsData, /// Is the object version currently being uploaded /// - /// matches only multipart uploads if check_multipart is Some(true) - /// matches only non-multipart uploads if check_multipart is Some(false) - /// matches both if check_multipart is None + /// matches only multipart uploads if `check_multipart` is Some(true) + /// matches only non-multipart uploads if `check_multipart` is Some(false) + /// matches both if `check_multipart` is None IsUploading { check_multipart: Option }, } diff --git a/src/model/snapshot.rs b/src/model/snapshot.rs index f1ac647d..d09e8e4a 100644 --- a/src/model/snapshot.rs +++ b/src/model/snapshot.rs @@ -20,7 +20,7 @@ static SNAPSHOT_MUTEX: Mutex<()> = Mutex::new(()); // ================ snapshotting logic ===================== -/// Run snapshot_metadata in a blocking thread and async await on it +/// Run `snapshot_metadata` in a blocking thread and async await on it pub async fn async_snapshot_metadata(garage: &Arc) -> Result<(), Error> { let garage = garage.clone(); let worker = tokio::task::spawn_blocking(move || snapshot_metadata(&garage)); diff --git a/src/net/bytes_buf.rs b/src/net/bytes_buf.rs index e96184ae..a3a5ca34 100644 --- a/src/net/bytes_buf.rs +++ b/src/net/bytes_buf.rs @@ -17,7 +17,7 @@ pub struct BytesBuf { } impl BytesBuf { - /// Creates a new empty BytesBuf + /// Creates a new empty `BytesBuf` pub fn new() -> Self { Self { buf: VecDeque::new(), @@ -25,13 +25,13 @@ impl BytesBuf { } } - /// Returns the number of bytes stored in the BytesBuf + /// Returns the number of bytes stored in the `BytesBuf` #[inline] pub fn len(&self) -> usize { self.buf_len } - /// Returns true iff the BytesBuf contains zero bytes + /// Returns true iff the `BytesBuf` contains zero bytes #[inline] pub fn is_empty(&self) -> bool { self.buf_len == 0 @@ -63,7 +63,7 @@ impl BytesBuf { } } - /// Takes at most max_len bytes from the left of the buffer + /// Takes at most `max_len` bytes from the left of the buffer pub fn take_max(&mut self, max_len: usize) -> Bytes { if self.buf_len <= max_len { self.take_all() @@ -73,7 +73,7 @@ impl BytesBuf { } /// Take exactly len bytes from the left of the buffer, returns None if - /// the BytesBuf doesn't contain enough data + /// the `BytesBuf` doesn't contain enough data pub fn take_exact(&mut self, len: usize) -> Option { if self.buf_len < len { None diff --git a/src/net/message.rs b/src/net/message.rs index b511cb20..6774520f 100644 --- a/src/net/message.rs +++ b/src/net/message.rs @@ -101,9 +101,9 @@ pub trait Message: Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static // ---- /// The `Req` is a helper object used to create requests and attach them -/// a stream of data. If the stream is a fixed Bytes and not a ByteStream, +/// a stream of data. If the stream is a fixed Bytes and not a `ByteStream`, /// `Req` is cheaply cloneable to allow the request to be sent to different -/// peers (Clone will panic if the stream is a ByteStream). +/// peers (Clone will panic if the stream is a `ByteStream`). pub struct Req { pub(crate) msg: Arc, pub(crate) msg_ser: Option, @@ -382,7 +382,7 @@ impl AttachedStream { // ---- ---- -/// Encoding for requests into a ByteStream: +/// Encoding for requests into a `ByteStream`: /// - priority: u8 /// - path length: u8 /// - path: [u8; path length] @@ -457,7 +457,7 @@ impl ReqEnc { } } -/// Encoding for responses into a ByteStream: +/// Encoding for responses into a `ByteStream`: /// /// IF SUCCESS: /// - 0: u8 @@ -468,7 +468,7 @@ impl ReqEnc { /// IF ERROR: /// - message length + 1: u8 /// - error code: u8 -/// - message: [u8; message_length] +/// - message: [u8; `message_length`] pub(crate) struct RespEnc { msg: Bytes, stream: Option, diff --git a/src/net/netapp.rs b/src/net/netapp.rs index 36c6fc88..5ffc2d7f 100644 --- a/src/net/netapp.rs +++ b/src/net/netapp.rs @@ -34,12 +34,12 @@ pub type NetworkKey = sodiumoxide::crypto::auth::Key; /// composed of 8 bytes for Netapp version and 8 bytes for client version pub(crate) type VersionTag = [u8; 16]; -/// Value of garage_net version used in the version tag -/// We are no longer using prefix `netapp` as garage_net is forked from the netapp crate. -/// Since Garage v1.0, we have replaced the prefix by `grgnet` (shorthand for garage_net). +/// Value of `garage_net` version used in the version tag +/// We are no longer using prefix `netapp` as `garage_net` is forked from the netapp crate. +/// Since Garage v1.0, we have replaced the prefix by `grgnet` (shorthand for `garage_net`). pub(crate) const NETAPP_VERSION_TAG: u64 = 0x6772676e65740010; // grgnet 0x0010 (1.0) -/// HelloMessage is sent by the client on a Netapp connection to indicate +/// `HelloMessage` is sent by the client on a Netapp connection to indicate /// that they are also a server and ready to receive incoming connections /// at the specified address and port. If the client doesn't know their /// public address, they don't need to specify it and we look at the @@ -57,9 +57,9 @@ impl Message for HelloMessage { type OnConnectHandler = Box; type OnDisconnectHandler = Box; -/// NetApp is the main class that handles incoming and outgoing connections. +/// `NetApp` is the main class that handles incoming and outgoing connections. /// -/// NetApp can be used in a stand-alone fashion or together with a peering strategy. +/// `NetApp` can be used in a stand-alone fashion or together with a peering strategy. /// If using it alone, you will want to set `on_connect` and `on_disconnect` events /// in order to manage information about the current peer list. pub struct NetApp { @@ -91,7 +91,7 @@ struct ListenParams { } impl NetApp { - /// Creates a new instance of NetApp, which can serve either as a full p2p node, + /// Creates a new instance of `NetApp`, which can serve either as a full p2p node, /// or just as a passive client. To upgrade to a full p2p node, spawn a listener /// using `.listen()` /// @@ -186,7 +186,7 @@ impl NetApp { /// Main listening process for our app. This future runs during the whole /// run time of our application. - /// If this is not called, the NetApp instance remains a passive client. + /// If this is not called, the `NetApp` instance remains a passive client. pub async fn listen( self: Arc, listen_addr: SocketAddr, diff --git a/src/net/peering.rs b/src/net/peering.rs index 5d942b5c..f9e266b4 100644 --- a/src/net/peering.rs +++ b/src/net/peering.rs @@ -119,7 +119,7 @@ impl PeerInfo { } } -/// PeerConnState: possible states for our tentative connections to given peer +/// `PeerConnState`: possible states for our tentative connections to given peer /// This structure is only interested in recording connection info for outgoing /// TCP connections #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/src/net/recv.rs b/src/net/recv.rs index 24961903..b7acb612 100644 --- a/src/net/recv.rs +++ b/src/net/recv.rs @@ -42,8 +42,8 @@ impl Drop for Sender { } } -/// The RecvLoop trait, which is implemented both by the client and the server -/// connection objects (ServerConn and ClientConn) adds a method `.recv_loop()` +/// The `RecvLoop` trait, which is implemented both by the client and the server +/// connection objects (`ServerConn` and `ClientConn`) adds a method `.recv_loop()` /// and a prototype of a handler for received messages `.recv_handler()` that /// must be filled by implementors. `.recv_loop()` receives messages in a loop /// according to the protocol defined above: chunks of message in progress of being diff --git a/src/net/send.rs b/src/net/send.rs index 6f1ac02c..16248f66 100644 --- a/src/net/send.rs +++ b/src/net/send.rs @@ -264,8 +264,8 @@ impl DataFrame { } } -/// The SendLoop trait, which is implemented both by the client and the server -/// connection objects (ServerConna and ClientConn) adds a method `.send_loop()` +/// The `SendLoop` trait, which is implemented both by the client and the server +/// connection objects (`ServerConna` and `ClientConn`) adds a method `.send_loop()` /// that takes a channel of messages to send and an asynchronous writer, /// and sends messages from the channel to the async writer, putting them in a queue /// before being sent and doing the round-robin sending strategy. diff --git a/src/net/stream.rs b/src/net/stream.rs index c973f9a7..93971ba7 100644 --- a/src/net/stream.rs +++ b/src/net/stream.rs @@ -14,18 +14,18 @@ use crate::bytes_buf::BytesBuf; /// When sent through Netapp, the Vec may be split in smaller chunk in such a way /// consecutive Vec may get merged, but Vec and error code may not be reordered /// -/// Items sent in the ByteStream may be errors of type `std::io::Error`. -/// An error indicates the end of the ByteStream: a reader should no longer read +/// Items sent in the `ByteStream` may be errors of type `std::io::Error`. +/// An error indicates the end of the `ByteStream`: a reader should no longer read /// after receiving an error, and a writer should stop writing after sending an error. pub type ByteStream = Pin + Send + Sync>>; -/// A packet sent in a ByteStream, which may contain either +/// A packet sent in a `ByteStream`, which may contain either /// a Bytes object or an error pub type Packet = Result; // ---- -/// A helper struct to read defined lengths of data from a BytesStream +/// A helper struct to read defined lengths of data from a `BytesStream` pub struct ByteStreamReader { stream: ByteStream, buf: BytesBuf, @@ -201,7 +201,7 @@ pub fn stream_asyncread(stream: ByteStream) -> impl AsyncRead + Send + Sync + 's tokio_util::io::StreamReader::new(stream) } -/// Reads all of the content of a `ByteStream` into a BytesBuf +/// Reads all of the content of a `ByteStream` into a `BytesBuf` /// that contains everything pub async fn read_stream_to_end(mut stream: ByteStream) -> Result { let mut buf = BytesBuf::new(); diff --git a/src/net/util.rs b/src/net/util.rs index 35a3be1e..ab09e68f 100644 --- a/src/net/util.rs +++ b/src/net/util.rs @@ -7,7 +7,7 @@ use tokio::sync::watch; use crate::netapp::*; -/// Utility function: encodes any serializable value in MessagePack binary format +/// Utility function: encodes any serializable value in `MessagePack` binary format /// using the RMP library. /// /// Field names and variant names are included in the serialization. @@ -80,7 +80,7 @@ pub fn parse_and_resolve_peer_addr(peer: &str) -> Option<(NodeID, Vec Option<(NodeID, Vec)> { let delim = peer.find('@')?; let (key, host) = peer.split_at(delim); diff --git a/src/rpc/layout/graph_algo.rs b/src/rpc/layout/graph_algo.rs index 3450b8a1..c02da729 100644 --- a/src/rpc/layout/graph_algo.rs +++ b/src/rpc/layout/graph_algo.rs @@ -42,7 +42,7 @@ impl Edge for WeightedEdge {} /// Struct for the graph structure. We do encapsulation here to be able to both /// provide user friendly Vertex enum to address vertices, and to use internally usize -/// indices and Vec instead of HashMap in the graph algorithm to optimize execution speed. +/// indices and Vec instead of `HashMap` in the graph algorithm to optimize execution speed. pub struct Graph { vertex_to_id: HashMap, id_to_vertex: Vec, @@ -253,7 +253,7 @@ impl Graph { /// This function takes a flow, and a cost function on the edges, and tries to find an /// equivalent flow with a better cost, by finding improving overflow cycles. It uses - /// as subroutine the Bellman Ford algorithm run up to path_length. + /// as subroutine the Bellman Ford algorithm run up to `path_length`. /// We assume that the cost of edge (u,v) is the opposite of the cost of (v,u), and /// only one needs to be present in the cost function. pub fn optimize_flow_with_cost( @@ -290,7 +290,7 @@ impl Graph { Ok(()) } - /// Construct the weighted graph G_f from the flow and the cost function + /// Construct the weighted graph `G_f` from the flow and the cost function fn build_cost_graph(&self, cost: &CostFunction) -> Result, String> { let mut g = Graph::::new(&self.id_to_vertex); let nb_vertices = self.id_to_vertex.len(); @@ -323,11 +323,11 @@ impl Graph { Ok(()) } - /// This function lists the negative cycles it manages to find after path_length + /// This function lists the negative cycles it manages to find after `path_length` /// iterations of the main loop of the Bellman-Ford algorithm. For the classical - /// algorithm, path_length needs to be equal to the number of vertices. However, + /// algorithm, `path_length` needs to be equal to the number of vertices. However, /// for particular graph structures like in our case, the algorithm is still correct - /// when path_length is the length of the longest possible simple path. + /// when `path_length` is the length of the longest possible simple path. /// See the formal description of the algorithm for more details. fn list_negative_cycles(&self, path_length: usize) -> Vec> { let nb_vertices = self.graph.len(); diff --git a/src/rpc/layout/helper.rs b/src/rpc/layout/helper.rs index 7ee0721a..2fa6f913 100644 --- a/src/rpc/layout/helper.rs +++ b/src/rpc/layout/helper.rs @@ -162,7 +162,7 @@ impl LayoutHelper { } /// Returns the latest layout version for which it is safe to read data from, - /// i.e. the version whose version number is sync_map_min + /// i.e. the version whose version number is `sync_map_min` pub fn read_version(&self) -> Result<&LayoutVersion, Error> { let sync_min = self.sync_map_min; let versions = self.versions()?; diff --git a/src/rpc/layout/mod.rs b/src/rpc/layout/mod.rs index 702bd681..e565d13e 100644 --- a/src/rpc/layout/mod.rs +++ b/src/rpc/layout/mod.rs @@ -23,7 +23,7 @@ pub use version::*; /// A partition id, which is stored on 16 bits /// i.e. we have up to 2**16 partitions. -/// (in practice we have exactly 2**PARTITION_BITS partitions) +/// (in practice we have exactly 2**`PARTITION_BITS` partitions) pub type Partition = u16; // TODO: make this constant parametrizable in the config file @@ -114,7 +114,7 @@ mod v09 { /// to know to what extent does it change with the layout update. pub partition_size: u64, /// Parameters used to compute the assignment currently given by - /// ring_assignment_data + /// `ring_assignment_data` pub parameters: LayoutParameters, pub roles: LwwMap, @@ -229,7 +229,7 @@ mod v010 { use std::collections::BTreeMap; pub use v09::{LayoutParameters, NodeRole, NodeRoleV, ZoneRedundancy}; - /// Number of old (non-live) versions to keep, see LayoutHistory::old_versions + /// Number of old (non-live) versions to keep, see `LayoutHistory::old_versions` pub const OLD_VERSION_COUNT: usize = 5; /// The history of cluster layouts, with trackers to keep a record @@ -238,8 +238,8 @@ mod v010 { pub struct LayoutHistory { /// The versions currently in use in the cluster pub versions: Vec, - /// At most 5 of the previous versions, not used by the garage_table - /// module, but useful for the garage_block module to find data blocks + /// At most 5 of the previous versions, not used by the `garage_table` + /// module, but useful for the `garage_block` module to find data blocks /// that have not yet been moved pub old_versions: Vec, @@ -260,7 +260,7 @@ mod v010 { /// Roles assigned to nodes in this version pub roles: LwwMap, /// Parameters used to compute the assignment currently given by - /// ring_assignment_data + /// `ring_assignment_data` pub parameters: LayoutParameters, /// The number of replicas for each data partition @@ -269,17 +269,17 @@ mod v010 { /// to know to what extent does it change with the layout update. pub partition_size: u64, - /// node_id_vec: a vector of node IDs with a role assigned + /// `node_id_vec`: a vector of node IDs with a role assigned /// in the system (this includes gateway nodes). /// The order here is different than the vec stored by `roles`, because: /// 1. non-gateway nodes are first so that they have lower numbers /// 2. nodes that don't have a role are excluded (but they need to /// stay in the CRDT as tombstones) pub node_id_vec: Vec, - /// number of non-gateway nodes, which are the first ids in node_id_vec + /// number of non-gateway nodes, which are the first ids in `node_id_vec` pub nongateway_node_count: usize, /// The assignation of data partitions to nodes, the values - /// are indices in node_id_vec + /// are indices in `node_id_vec` #[serde(with = "serde_bytes")] pub ring_assignment_data: Vec, } diff --git a/src/rpc/layout/version.rs b/src/rpc/layout/version.rs index 80a83145..06a1392c 100644 --- a/src/rpc/layout/version.rs +++ b/src/rpc/layout/version.rs @@ -164,7 +164,7 @@ impl LayoutVersion { total_capacity } - /// Returns the effective value of the zone_redundancy parameter + /// Returns the effective value of the `zone_redundancy` parameter pub(crate) fn effective_zone_redundancy(&self) -> usize { match self.parameters.zone_redundancy { ZoneRedundancy::AtLeast(v) => v, @@ -311,7 +311,7 @@ impl LayoutVersion { /// the former assignment (if any) to minimize the amount of /// data to be moved. /// Staged role changes must be merged with nodes roles before calling this function, - /// hence it must only be called from apply_staged_changes() and hence is not public. + /// hence it must only be called from `apply_staged_changes()` and hence is not public. fn calculate_partition_assignment(&mut self) -> Result { // We update the node ids, since the node role list might have changed with the // changes in the layout. We retrieve the old_assignment reframed with new ids @@ -402,11 +402,11 @@ impl LayoutVersion { Ok(msg) } - /// The LwwMap of node roles might have changed. This function updates the node_id_vec + /// The `LwwMap` of node roles might have changed. This function updates the `node_id_vec` /// and returns the assignment given by ring, with the new indices of the nodes, and /// None if the node is not present anymore. - /// We work with the assumption that only this function and calculate_new_assignment - /// do modify assignment_ring and node_id_vec. + /// We work with the assumption that only this function and `calculate_new_assignment` + /// do modify `assignment_ring` and `node_id_vec`. fn update_node_id_vec(&mut self) -> Result>>, Error> { // (1) We compute the new node list // Non gateway nodes should be coded on 8bits, hence they must be first in the list @@ -488,7 +488,7 @@ impl LayoutVersion { } /// This function generates ids for the zone of the nodes appearing in - /// self.node_id_vec. + /// `self.node_id_vec`. pub(crate) fn generate_nongateway_zone_ids( &self, ) -> Result<(Vec, HashMap), Error> { @@ -560,7 +560,7 @@ impl LayoutVersion { /// Generates the graph to compute the maximal flow corresponding to the optimal /// partition assignment. - /// exclude_assoc is the set of (partition, node) association that we are forbidden + /// `exclude_assoc` is the set of (partition, node) association that we are forbidden /// to use (hence we do not add the corresponding edge to the graph). This parameter /// is used to compute a first flow that uses only edges appearing in the previous /// assignment. This produces a solution that heuristically should be close to the diff --git a/src/rpc/metrics.rs b/src/rpc/metrics.rs index 61f8fa79..0676dec0 100644 --- a/src/rpc/metrics.rs +++ b/src/rpc/metrics.rs @@ -1,6 +1,6 @@ use opentelemetry::{global, metrics::*}; -/// TableMetrics reference all counter used for metrics +/// `TableMetrics` reference all counter used for metrics pub struct RpcMetrics { pub(crate) rpc_counter: Counter, pub(crate) rpc_timeout_counter: Counter, diff --git a/src/rpc/rpc_helper.rs b/src/rpc/rpc_helper.rs index 0f744f5b..d7ec5242 100644 --- a/src/rpc/rpc_helper.rs +++ b/src/rpc/rpc_helper.rs @@ -66,7 +66,7 @@ impl Clone for RequestStrategy<()> { } impl RequestStrategy<()> { - /// Create a RequestStrategy with default timeout and not interrupting when quorum reached + /// Create a `RequestStrategy` with default timeout and not interrupting when quorum reached pub fn with_priority(prio: RequestPriority) -> Self { RequestStrategy { rs_quorum: None, @@ -109,7 +109,7 @@ impl RequestStrategy { self.rs_timeout = Timeout::Custom(timeout); self } - /// Extract drop_on_complete item + /// Extract `drop_on_complete` item fn extract_drop_on_complete(self) -> (RequestStrategy<()>, T) { ( RequestStrategy { @@ -272,7 +272,7 @@ impl RpcHelper { /// Make a RPC call to multiple servers, returning either a Vec of responses, /// or an error if quorum could not be reached due to too many errors /// - /// If RequestStrategy has send_all_at_once set, then all requests will be + /// If `RequestStrategy` has `send_all_at_once` set, then all requests will be /// sent at once, and `try_call_many` will return as soon as a quorum of /// responses is achieved, dropping and cancelling the remaining requests. /// @@ -413,7 +413,7 @@ impl RpcHelper { /// Make a RPC call to multiple servers, returning either a Vec of responses, /// or an error if quorum could not be reached due to too many errors /// - /// Contrary to try_call_many, this function is especially made for broadcast + /// Contrary to `try_call_many`, this function is especially made for broadcast /// write operations. In particular: /// /// - The request are sent to all specified nodes as soon as `try_write_many_sets` diff --git a/src/rpc/system.rs b/src/rpc/system.rs index 6adb13a1..06633b78 100644 --- a/src/rpc/system.rs +++ b/src/rpc/system.rs @@ -57,7 +57,7 @@ pub enum SystemRpc { Ok, /// Request to connect to a specific node (in `@:` format, pubkey = full-length node ID) Connect(String), - /// Advertise Garage status. Answered with another AdvertiseStatus. + /// Advertise Garage status. Answered with another `AdvertiseStatus`. /// Exchanged with every node on a regular basis. AdvertiseStatus(NodeStatus), /// Get known nodes states @@ -65,9 +65,9 @@ pub enum SystemRpc { /// Return known nodes ReturnKnownNodes(Vec), - /// Ask other node its cluster layout. Answered with AdvertiseClusterLayout + /// Ask other node its cluster layout. Answered with `AdvertiseClusterLayout` PullClusterLayout, - /// Advertisement of cluster layout. Sent spontanously or in response to PullClusterLayout + /// Advertisement of cluster layout. Sent spontanously or in response to `PullClusterLayout` AdvertiseClusterLayout(LayoutHistory), /// Ask other node its cluster layout update trackers. PullClusterLayoutTrackers, @@ -908,7 +908,7 @@ impl NodeStatus { } /// Obtain the list of currently available IP addresses on all non-loopback -/// interfaces, optionally filtering them to be inside a given IpNet. +/// interfaces, optionally filtering them to be inside a given `IpNet`. fn get_default_ip(filter_ipnet: Option) -> Option { pnet_datalink::interfaces() .into_iter() diff --git a/src/rpc/system_metrics.rs b/src/rpc/system_metrics.rs index 937c6db2..23957399 100644 --- a/src/rpc/system_metrics.rs +++ b/src/rpc/system_metrics.rs @@ -5,7 +5,7 @@ use opentelemetry::{global, metrics::*, KeyValue}; use crate::system::{ClusterHealthStatus, System}; -/// TableMetrics reference all counter used for metrics +/// `TableMetrics` reference all counter used for metrics pub struct SystemMetrics { // Static values pub(crate) _garage_build_info: ValueObserver, diff --git a/src/table/gc.rs b/src/table/gc.rs index 1ef7d471..af84b9df 100644 --- a/src/table/gc.rs +++ b/src/table/gc.rs @@ -334,7 +334,7 @@ impl Worker for GcWorker { } } -/// An entry stored in the gc_todo db tree associated with the table +/// An entry stored in the `gc_todo` db tree associated with the table /// Contains helper function for parsing, saving, and removing /// such entry in the db /// @@ -352,7 +352,7 @@ pub(crate) struct GcTodoEntry { } impl GcTodoEntry { - /// Creates a new GcTodoEntry (not saved in the db) from its components: + /// Creates a new `GcTodoEntry` (not saved in the db) from its components: /// the key of an entry in the table, and the hash of the associated /// serialized value pub(crate) fn new(key: Vec, value_hash: Hash) -> Self { @@ -364,7 +364,7 @@ impl GcTodoEntry { } } - /// Parses a GcTodoEntry from a (k, v) pair stored in the gc_todo tree + /// Parses a `GcTodoEntry` from a (k, v) pair stored in the `gc_todo` tree pub(crate) fn parse(db_k: &[u8], db_v: &[u8]) -> Self { Self { tombstone_timestamp: u64::from_be_bytes(db_k[0..8].try_into().unwrap()), @@ -374,13 +374,13 @@ impl GcTodoEntry { } } - /// Saves the GcTodoEntry in the gc_todo tree + /// Saves the `GcTodoEntry` in the `gc_todo` tree pub(crate) fn save(&self, gc_todo_tree: &db::Tree) -> Result<(), Error> { gc_todo_tree.insert(self.todo_table_key(), self.value_hash.as_slice())?; Ok(()) } - /// Removes the GcTodoEntry from the gc_todo tree if the + /// Removes the `GcTodoEntry` from the `gc_todo` tree if the /// hash of the serialized value is the same here as in the tree. /// This is useful to remove a todo entry only under the condition /// that it has not changed since the time it was read, i.e. diff --git a/src/table/metrics.rs b/src/table/metrics.rs index 8d2047e2..b1a787f2 100644 --- a/src/table/metrics.rs +++ b/src/table/metrics.rs @@ -2,7 +2,7 @@ use opentelemetry::{global, metrics::*, KeyValue}; use garage_db as db; -/// TableMetrics reference all counter used for metrics +/// `TableMetrics` reference all counter used for metrics pub struct TableMetrics { pub(crate) _table_size: ValueObserver, pub(crate) _merkle_tree_size: ValueObserver, diff --git a/src/table/schema.rs b/src/table/schema.rs index fc1a465e..e3b81bdb 100644 --- a/src/table/schema.rs +++ b/src/table/schema.rs @@ -22,7 +22,7 @@ impl PartitionKey for String { } } -/// Values of type FixedBytes32 are assumed to be random, +/// Values of type `FixedBytes32` are assumed to be random, /// either a hash or a random UUID. This means we can use /// them directly as an index into the hash table. impl PartitionKey for FixedBytes32 { diff --git a/src/util/background/mod.rs b/src/util/background/mod.rs index 1fc70d19..6b911b5e 100644 --- a/src/util/background/mod.rs +++ b/src/util/background/mod.rs @@ -27,7 +27,7 @@ pub struct WorkerInfo { pub last_error: Option<(String, u64)>, } -/// WorkerStatus is a struct returned by the worker with a bunch of canonical +/// `WorkerStatus` is a struct returned by the worker with a bunch of canonical /// fields to indicate their status to CLI users. All fields are optional. #[derive(Clone, Debug, Default)] pub struct WorkerStatus { @@ -39,7 +39,7 @@ pub struct WorkerStatus { } impl BackgroundRunner { - /// Create a new BackgroundRunner + /// Create a new `BackgroundRunner` pub fn new(stop_signal: watch::Receiver) -> (Arc, tokio::task::JoinHandle<()>) { let (send_worker, worker_out) = mpsc::unbounded_channel::>(); diff --git a/src/util/background/worker.rs b/src/util/background/worker.rs index 9028a052..cf013e73 100644 --- a/src/util/background/worker.rs +++ b/src/util/background/worker.rs @@ -34,11 +34,11 @@ pub trait Worker: Send { } /// Work: do a basic unit of work, if one is available (otherwise, should return - /// WorkerState::Idle immediately). We will do our best to not interrupt this future in the + /// `WorkerState::Idle` immediately). We will do our best to not interrupt this future in the /// middle of processing, it will only be interrupted at the last minute when Garage is trying /// to exit and this hasn't returned yet. This function may return an error to indicate that /// its unit of work could not be processed due to an error: the error will be logged and - /// .work() will be called again after a short delay. + /// .`work()` will be called again after a short delay. async fn work(&mut self, must_exit: &mut watch::Receiver) -> Result; /// Wait for work: await for some task to become available. This future can be interrupted in diff --git a/src/util/config.rs b/src/util/config.rs index bc476a35..c4013fb6 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -47,7 +47,7 @@ pub struct Config { /// Maximum number of parallel block writes per PUT request /// Higher values improve throughput but increase memory usage - /// Default: 3, Recommended: 10-30 for NVMe, 3-10 for HDD + /// Default: 3, Recommended: 10-30 for `NVMe`, 3-10 for HDD #[serde(default = "default_block_max_concurrent_writes_per_request")] pub block_max_concurrent_writes_per_request: usize, /// Number of replicas. Can be any positive integer, but uneven numbers are more favorable. @@ -95,7 +95,7 @@ pub struct Config { pub rpc_secret_file: Option, /// Address to bind for RPC pub rpc_bind_addr: SocketAddr, - /// Bind outgoing sockets to rpc_bind_addr's IP address as well + /// Bind outgoing sockets to `rpc_bind_addr`'s IP address as well #[serde(default)] pub rpc_bind_outgoing: bool, /// Public IP address of this node @@ -154,7 +154,7 @@ pub struct Config { pub allow_punycode: bool, } -/// Value for data_dir: either a single directory or a list of dirs with attributes +/// Value for `data_dir`: either a single directory or a list of dirs with attributes #[derive(Deserialize, Debug, Clone)] #[serde(untagged)] pub enum DataDirEnum { @@ -166,7 +166,7 @@ pub enum DataDirEnum { pub struct DataDir { /// Path to the data directory pub path: PathBuf, - /// Capacity of the drive (required if read_only is false) + /// Capacity of the drive (required if `read_only` is false) #[serde(default)] pub capacity: Option, /// Whether this is a legacy read-only path (capacity should be None) diff --git a/src/util/crdt/crdt.rs b/src/util/crdt/crdt.rs index f2cfd464..ebdc66d1 100644 --- a/src/util/crdt/crdt.rs +++ b/src/util/crdt/crdt.rs @@ -29,10 +29,10 @@ pub trait Crdt { /// `Option` implements Crdt for any type T, even if T doesn't implement CRDT itself: when /// different values are detected, they are always merged to None. This can be used for value /// types which shoulnd't be merged, instead of trying to merge things when we know we don't want -/// to merge them (which is what the AutoCrdt trait is used for most of the time). This cases -/// arises very often, for example with a Lww or a LwwMap: the value type has to be a CRDT so that +/// to merge them (which is what the `AutoCrdt` trait is used for most of the time). This cases +/// arises very often, for example with a Lww or a `LwwMap`: the value type has to be a CRDT so that /// we have a rule for what to do when timestamps aren't enough to disambiguate (in a distributed -/// system, anything can happen!), and with AutoCrdt the rule is to make an arbitrary (but +/// system, anything can happen!), and with `AutoCrdt` the rule is to make an arbitrary (but /// deterministic) choice between the two. When using an `Option` instead with this impl, ambiguity /// cases are explicitly stored as None, which allows us to detect the ambiguity and handle it in /// the way we want. (this can only work if we are happy with losing the value when an ambiguity @@ -52,7 +52,7 @@ where /// defined by the merge rule: `a ⊔ b = max(a, b)`. Implement this trait for your type /// to enable this behavior. pub trait AutoCrdt: Ord + Clone + std::fmt::Debug { - /// WARN_IF_DIFFERENT: emit a warning when values differ. Set this to true if + /// `WARN_IF_DIFFERENT`: emit a warning when values differ. Set this to true if /// different values in your application should never happen. Set this to false /// if you are actually relying on the semantics of `a ⊔ b = max(a, b)`. const WARN_IF_DIFFERENT: bool; diff --git a/src/util/crdt/lww_map.rs b/src/util/crdt/lww_map.rs index def0ebeb..20a23913 100644 --- a/src/util/crdt/lww_map.rs +++ b/src/util/crdt/lww_map.rs @@ -19,7 +19,7 @@ use crate::crdt::crdt::*; /// Internally, the map is stored as a vector of keys and values, sorted by ascending key order. /// This is why the key type `K` must implement `Ord` (and also to ensure a unique serialization, /// such that two values can be compared for equality based on their hashes). As a consequence, -/// insertions take `O(n)` time. This means that LWWMap should be used for reasonably small maps. +/// insertions take `O(n)` time. This means that `LWWMap` should be used for reasonably small maps. /// However, note that even if we were using a more efficient data structure such as a `BTreeMap`, /// the serialization cost `O(n)` would still have to be paid at each modification, so we are /// actually not losing anything here. diff --git a/src/util/data.rs b/src/util/data.rs index eaf6e9dc..e4ce316b 100644 --- a/src/util/data.rs +++ b/src/util/data.rs @@ -73,7 +73,7 @@ impl FixedBytes32 { pub fn to_vec(self) -> Vec { self.0.to_vec() } - /// Try building a FixedBytes32 from a slice + /// Try building a `FixedBytes32` from a slice /// Return None if the slice is not 32 bytes long pub fn try_from(by: &[u8]) -> Option { if by.len() != 32 { diff --git a/src/util/encode.rs b/src/util/encode.rs index 3d989b7e..503d979d 100644 --- a/src/util/encode.rs +++ b/src/util/encode.rs @@ -1,7 +1,7 @@ use serde::{Deserialize, Serialize}; -/// Serialize to MessagePack, without versioning -/// (see garage_util::migrate for functions that manage versioned +/// Serialize to `MessagePack`, without versioning +/// (see `garage_util::migrate` for functions that manage versioned /// data formats) pub fn nonversioned_encode(val: &T) -> Result, rmp_serde::encode::Error> where @@ -13,8 +13,8 @@ where Ok(wr) } -/// Deserialize from MessagePack, without versioning -/// (see garage_util::migrate for functions that manage versioned +/// Deserialize from `MessagePack`, without versioning +/// (see `garage_util::migrate` for functions that manage versioned /// data formats) pub fn nonversioned_decode(bytes: &[u8]) -> Result where diff --git a/src/util/error.rs b/src/util/error.rs index 043d0dce..c3d4ab58 100644 --- a/src/util/error.rs +++ b/src/util/error.rs @@ -129,7 +129,7 @@ where } } -/// Trait to map any error type to Error::Message +/// Trait to map any error type to `Error::Message` pub trait OkOrMessage { type S; fn ok_or_message>(self, message: M) -> Result; diff --git a/src/util/migrate.rs b/src/util/migrate.rs index 45147c74..0cb7da93 100644 --- a/src/util/migrate.rs +++ b/src/util/migrate.rs @@ -54,7 +54,7 @@ impl Migrate for T { } } -/// Internal type used by InitialFormat, not meant for general use. +/// Internal type used by `InitialFormat`, not meant for general use. #[derive(Serialize, Deserialize)] pub enum NoPrevious {} From f59a8b7f621b0abf8c8e31b7cdd8994a7154b16c Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Mon, 26 Jan 2026 14:25:05 +0100 Subject: [PATCH 3/8] style: corrects the use of ';' to improve readability - remove unnecessary semicolon and enable lint warning: unnecessary semicolon help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#unnecessary_semicolon - add `;` to the last statement for consitent formatting and enable lint `clippy::semicolon_if_nothing_returned` warning: consider adding a `;` to the last statement for consistent formatting help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#semicolon_if_nothing_returned --- Cargo.toml | 2 ++ src/api/admin/bucket.rs | 8 ++++---- src/api/admin/openapi.rs | 2 +- src/api/admin/router_v0.rs | 2 +- src/api/admin/router_v1.rs | 2 +- src/api/admin/router_v2.rs | 2 +- src/api/common/generic_server.rs | 4 ++-- src/api/common/signature/body.rs | 2 +- src/api/k2v/router.rs | 2 +- src/api/s3/encryption.rs | 4 ++-- src/api/s3/list.rs | 10 +++++----- src/api/s3/multipart.rs | 2 +- src/api/s3/put.rs | 8 ++++---- src/api/s3/router.rs | 8 ++++---- src/block/layout.rs | 2 +- src/block/metrics.rs | 4 ++-- src/block/rc.rs | 6 +++--- src/block/repair.rs | 8 ++++---- src/block/resync.rs | 2 +- src/db/sqlite_adapter.rs | 2 +- src/garage/cli/remote/layout.rs | 2 +- src/garage/cli/remote/worker.rs | 2 +- src/garage/tests/s3/list.rs | 4 ++-- src/model/helper/locked.rs | 2 +- src/model/k2v/seen.rs | 2 +- src/net/client.rs | 2 +- src/net/error.rs | 2 +- src/net/netapp.rs | 2 +- src/net/recv.rs | 2 +- src/net/send.rs | 4 ++-- src/net/test.rs | 4 ++-- src/rpc/consul.rs | 2 +- src/rpc/kubernetes.rs | 4 ++-- src/rpc/layout/version.rs | 2 +- src/rpc/rpc_helper.rs | 4 ++-- src/rpc/system.rs | 8 ++++---- src/rpc/system_metrics.rs | 4 ++-- src/web/web_server.rs | 6 +++--- 38 files changed, 71 insertions(+), 69 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6d701055..6bd3d32a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -183,3 +183,5 @@ strip = "debuginfo" [workspace.lints.clippy] # pedantic lints configuration doc_markdown = "warn" +semicolon_if_nothing_returned = "warn" +unnecessary_semicolon = "warn" diff --git a/src/api/admin/bucket.rs b/src/api/admin/bucket.rs index 046ed44c..61be02d9 100644 --- a/src/api/admin/bucket.rs +++ b/src/api/admin/bucket.rs @@ -557,7 +557,7 @@ impl RequestHandler for AddBucketAliasRequest { BucketAliasEnum::Global { global_alias } => { helper .set_global_bucket_alias(bucket_id, &global_alias) - .await? + .await?; } BucketAliasEnum::Local { local_alias, @@ -565,7 +565,7 @@ impl RequestHandler for AddBucketAliasRequest { } => { helper .set_local_bucket_alias(bucket_id, &access_key_id, &local_alias) - .await? + .await?; } } @@ -591,7 +591,7 @@ impl RequestHandler for RemoveBucketAliasRequest { BucketAliasEnum::Global { global_alias } => { helper .unset_global_bucket_alias(bucket_id, &global_alias) - .await? + .await?; } BucketAliasEnum::Local { local_alias, @@ -599,7 +599,7 @@ impl RequestHandler for RemoveBucketAliasRequest { } => { helper .unset_local_bucket_alias(bucket_id, &access_key_id, &local_alias) - .await? + .await?; } } diff --git a/src/api/admin/openapi.rs b/src/api/admin/openapi.rs index c5936ade..c205213b 100644 --- a/src/api/admin/openapi.rs +++ b/src/api/admin/openapi.rs @@ -869,7 +869,7 @@ impl Modify for SecurityAddon { components.add_security_scheme( "bearerAuth", SecurityScheme::Http(Http::builder().scheme(HttpAuthScheme::Bearer).build()), - ) + ); } } diff --git a/src/api/admin/router_v0.rs b/src/api/admin/router_v0.rs index 168c21d3..89390666 100644 --- a/src/api/admin/router_v0.rs +++ b/src/api/admin/router_v0.rs @@ -124,7 +124,7 @@ impl Endpoint { ]); if let Some(message) = query.nonempty_message() { - debug!("Unused query parameter: {}", message) + debug!("Unused query parameter: {}", message); } Ok(res) diff --git a/src/api/admin/router_v1.rs b/src/api/admin/router_v1.rs index 2fdb996d..79e4fac4 100644 --- a/src/api/admin/router_v1.rs +++ b/src/api/admin/router_v1.rs @@ -126,7 +126,7 @@ impl Endpoint { ]); if let Some(message) = query.nonempty_message() { - debug!("Unused query parameter: {}", message) + debug!("Unused query parameter: {}", message); } Ok(res) diff --git a/src/api/admin/router_v2.rs b/src/api/admin/router_v2.rs index 7fcce6e7..3a9a567d 100644 --- a/src/api/admin/router_v2.rs +++ b/src/api/admin/router_v2.rs @@ -89,7 +89,7 @@ impl AdminApiRequest { ]); if let Some(message) = query.nonempty_message() { - debug!("Unused query parameter: {}", message) + debug!("Unused query parameter: {}", message); } Ok(res) diff --git a/src/api/common/generic_server.rs b/src/api/common/generic_server.rs index 181b6231..0e97334a 100644 --- a/src/api/common/generic_server.rs +++ b/src/api/common/generic_server.rs @@ -125,7 +125,7 @@ impl ApiServer { } UnixOrTCPSocketAddress::UnixSocket(ref path) => { if path.exists() { - fs::remove_file(path)? + fs::remove_file(path)?; } let listener = UnixListener::bind(path)?; @@ -190,7 +190,7 @@ impl ApiServer { let mut http_error_builder = Response::builder().status(e.http_status_code()); if let Some(header_map) = http_error_builder.headers_mut() { - e.add_http_headers(header_map) + e.add_http_headers(header_map); } let http_error = http_error_builder.body(body)?; diff --git a/src/api/common/signature/body.rs b/src/api/common/signature/body.rs index 96be0d5b..0bace5ef 100644 --- a/src/api/common/signature/body.rs +++ b/src/api/common/signature/body.rs @@ -89,7 +89,7 @@ impl ReqBody { checksummer }) .await - .unwrap() + .unwrap(); } Err(frame) => { let trailers = frame.into_trailers().unwrap(); diff --git a/src/api/k2v/router.rs b/src/api/k2v/router.rs index 241bb9d2..4e50bfa6 100644 --- a/src/api/k2v/router.rs +++ b/src/api/k2v/router.rs @@ -90,7 +90,7 @@ impl Endpoint { }; if let Some(message) = query.nonempty_message() { - debug!("Unused query parameter: {}", message) + debug!("Unused query parameter: {}", message); } Ok((res, bucket)) } diff --git a/src/api/s3/encryption.rs b/src/api/s3/encryption.rs index 0312754e..1723b762 100644 --- a/src/api/s3/encryption.rs +++ b/src/api/s3/encryption.rs @@ -660,11 +660,11 @@ mod tests { #[tokio::test] async fn test_encrypt_block() { - test_block_enc(None).await + test_block_enc(None).await; } #[tokio::test] async fn test_encrypt_block_compressed() { - test_block_enc(Some(1)).await + test_block_enc(Some(1)).await; } } diff --git a/src/api/s3/list.rs b/src/api/s3/list.rs index f306a1e5..67d9922e 100644 --- a/src/api/s3/list.rs +++ b/src/api/s3/list.rs @@ -484,7 +484,7 @@ where iter.next(); } _ => (), - }; + } while let Some(object) = iter.peek() { if !object.key.starts_with(&query.prefix) { @@ -508,7 +508,7 @@ where ExtractionResult::NoMore => { return Ok(None); } - }; + } } if !server_more { @@ -756,7 +756,7 @@ impl Accumulator { None => Some(ExtractionResult::NoMore), } } - }; + } } } @@ -1069,7 +1069,7 @@ mod tests { assert_eq!(upload, Uuid::from([0x8f; 32])); } _ => panic!("wrong result"), - }; + } assert_eq!(acc.keys.len(), 2); assert_eq!( @@ -1098,7 +1098,7 @@ mod tests { match acc.extract(&(query().common), &start, &mut iter) { ExtractionResult::Extracted { key } if key.as_str() == "b" => (), _ => panic!("wrong result"), - }; + } } #[tokio::test] diff --git a/src/api/s3/multipart.rs b/src/api/s3/multipart.rs index fb246041..5e56408f 100644 --- a/src/api/s3/multipart.rs +++ b/src/api/s3/multipart.rs @@ -370,7 +370,7 @@ pub async fn handle_complete_multipart_upload( req_part.part_number, req_part.checksum, part.checksum ))); } - parts.push(*part) + parts.push(*part); } _ => return Err(Error::InvalidPart), } diff --git a/src/api/s3/put.rs b/src/api/s3/put.rs index 27f85697..303a586b 100644 --- a/src/api/s3/put.rs +++ b/src/api/s3/put.rs @@ -192,7 +192,7 @@ pub(crate) async fn save_stream> + Unpin>( meta.checksum = checksums.extract(Some(algo)); } } - }; + } let size = first_block.len() as u64; check_quotas(ctx, size, existing_object.as_ref()).await?; @@ -293,7 +293,7 @@ pub(crate) async fn save_stream> + Unpin>( meta.checksum = checksums.extract(Some(algo)); } } - }; + } // Verify quotas are respsected check_quotas(ctx, total_size, existing_object.as_ref()).await?; @@ -339,7 +339,7 @@ pub(crate) async fn check_quotas( let quotas = bucket_params.quotas.get(); if quotas.max_objects.is_none() && quotas.max_size.is_none() { return Ok(()); - }; + } let counters = garage .object_counter_table @@ -436,7 +436,7 @@ pub(crate) async fn read_and_put_blocks> + tracer.start("Hash block (md5, sha256)"), )) .await - .unwrap() + .unwrap(); } Err(e) => { block_tx2.send(Err(e)).await?; diff --git a/src/api/s3/router.rs b/src/api/s3/router.rs index ca01c3cd..3f2d9208 100644 --- a/src/api/s3/router.rs +++ b/src/api/s3/router.rs @@ -365,7 +365,7 @@ impl Endpoint { } if let Some(message) = query.nonempty_message() { - debug!("Unused query parameter: {}", message) + debug!("Unused query parameter: {}", message); } Ok((res, Some(bucket))) } @@ -580,7 +580,7 @@ impl Endpoint { pub fn authorization_type(&self) -> Authorization { if let Endpoint::ListBuckets = self { return Authorization::None; - }; + } let readonly = router_match! { @match self, @@ -725,7 +725,7 @@ mod tests { ) -> (Endpoint, Option) { let mut req = Request::builder().method(method).uri(uri); if let Some((k, v)) = header { - req = req.header(k, v) + req = req.header(k, v); } let req = req.body(()).unwrap(); @@ -859,7 +859,7 @@ mod tests { .body(()) .unwrap(); - assert!(Endpoint::from_request(&req, None).is_err()) + assert!(Endpoint::from_request(&req, None).is_err()); } #[test] diff --git a/src/block/layout.rs b/src/block/layout.rs index 918b556e..dd153d6e 100644 --- a/src/block/layout.rs +++ b/src/block/layout.rs @@ -159,7 +159,7 @@ impl DataLayout { for (idir, parts) in dir_prim.iter().enumerate() { for part in parts.iter() { assert!(part_prim[*part].is_none()); - part_prim[*part] = Some(idir as Idx) + part_prim[*part] = Some(idir as Idx); } } diff --git a/src/block/metrics.rs b/src/block/metrics.rs index ffed7d1d..7a07018c 100644 --- a/src/block/metrics.rs +++ b/src/block/metrics.rs @@ -52,7 +52,7 @@ impl BlockManagerMetrics { _rc_size: meter .u64_value_observer("block.rc_size", move |observer| { if let Ok(value) = rc_tree.approximate_len() { - observer.observe(value as u64, &[]) + observer.observe(value as u64, &[]); } }) .with_description("Number of blocks known to the reference counter") @@ -78,7 +78,7 @@ impl BlockManagerMetrics { _buffer_free_kb: meter .u64_value_observer("block.ram_buffer_free_kb", move |observer| { - observer.observe(buffer_semaphore.available_permits() as u64, &[]) + observer.observe(buffer_semaphore.available_permits() as u64, &[]); }) .with_description( "Available RAM in KiB to use for buffering data blocks to be written to remote nodes", diff --git a/src/block/rc.rs b/src/block/rc.rs index 24f67cf2..881df68b 100644 --- a/src/block/rc.rs +++ b/src/block/rc.rs @@ -37,7 +37,7 @@ impl BlockRc { match old_rc.increment().serialize() { Some(x) => tx.insert(&self.rc_table, hash, x)?, None => unreachable!(), - }; + } Ok(old_rc.is_zero()) } @@ -52,7 +52,7 @@ impl BlockRc { match new_rc.serialize() { Some(x) => tx.insert(&self.rc_table, hash, x)?, None => tx.remove(&self.rc_table, hash)?, - }; + } Ok(matches!(new_rc, RcEntry::Deletable { .. })) } @@ -72,7 +72,7 @@ impl BlockRc { tx.remove(&self.rc_table, hash)?; } _ => (), - }; + } Ok(()) })?; Ok(()) diff --git a/src/block/repair.rs b/src/block/repair.rs index e467229f..343574f8 100644 --- a/src/block/repair.rs +++ b/src/block/repair.rs @@ -127,7 +127,7 @@ impl Worker for RepairWorker { self.manager .resync .put_to_resync(&hash, Duration::from_secs(0))?; - self.next_start = Some(hash) + self.next_start = Some(hash); } Ok(WorkerState::Busy) @@ -440,7 +440,7 @@ impl Worker for ScrubWorker { Ok(cmd) => self.handle_cmd(cmd).await, Err(mpsc::error::TryRecvError::Disconnected) => return Ok(WorkerState::Done), Err(mpsc::error::TryRecvError::Empty) => (), - }; + } match &mut self.work { ScrubWorkerState::Running { iterator, t_cp } => { @@ -455,7 +455,7 @@ impl Worker for ScrubWorker { } Err(e) => return Err(e), _ => (), - }; + } if now - *t_cp > 60 * 1000 { self.persister @@ -570,7 +570,7 @@ impl Worker for RebalanceWorker { format!("Started: {}", msec_to_rfc3339(self.t_started)), ]; if let Some(t_fin) = self.t_finished { - freeform.push(format!("Finished: {}", msec_to_rfc3339(t_fin))) + freeform.push(format!("Finished: {}", msec_to_rfc3339(t_fin))); } WorkerStatus { progress: Some(format!("{:.2}%", self.block_iter.progress() * 100.)), diff --git a/src/block/resync.rs b/src/block/resync.rs index 28666a71..003c1172 100644 --- a/src/block/resync.rs +++ b/src/block/resync.rs @@ -588,7 +588,7 @@ impl Worker for ResyncWorker { async fn wait_for_work(&mut self) -> WorkerState { while self.index >= self.persister.get_with(|x| x.n_workers) { - self.manager.resync.notify.notified().await + self.manager.resync.notify.notified().await; } select! { diff --git a/src/db/sqlite_adapter.rs b/src/db/sqlite_adapter.rs index 832dab14..b640e273 100644 --- a/src/db/sqlite_adapter.rs +++ b/src/db/sqlite_adapter.rs @@ -564,7 +564,7 @@ fn bounds_sql<'r>(low: Bound<&'r [u8]>, high: Bound<&'r [u8]>) -> (String, Vec (), - }; + } match high { Bound::Included(b) => { diff --git a/src/garage/cli/remote/layout.rs b/src/garage/cli/remote/layout.rs index fe0e3713..10be1029 100644 --- a/src/garage/cli/remote/layout.rs +++ b/src/garage/cli/remote/layout.rs @@ -394,7 +394,7 @@ pub fn print_cluster_layout(layout: &GetClusterLayoutResponse, empty_msg: &str) role.zone, capacity_string(role.capacity), )); - }; + } } if table.len() > 1 { format_table(table); diff --git a/src/garage/cli/remote/worker.rs b/src/garage/cli/remote/worker.rs index 45f0b3cd..f1cf1636 100644 --- a/src/garage/cli/remote/worker.rs +++ b/src/garage/cli/remote/worker.rs @@ -102,7 +102,7 @@ impl Cli { s => { table.push(format!("Worker state:\t{}", format_worker_state(s))); } - }; + } if let Some(tql) = info.tranquility { table.push(format!("Tranquility:\t{}", tql)); } diff --git a/src/garage/tests/s3/list.rs b/src/garage/tests/s3/list.rs index 1b0c006d..8b423a55 100644 --- a/src/garage/tests/s3/list.rs +++ b/src/garage/tests/s3/list.rs @@ -123,7 +123,7 @@ async fn test_listobjectsv2() { (Some(k), None) if k.len() == 1 => cnt_key += 1, (None, Some(pfx)) if pfx.len() == 1 => cnt_pfx += 1, _ => unreachable!("logic error"), - }; + } if next.is_none() { break; } @@ -331,7 +331,7 @@ async fn test_listobjectsv1() { (Some(k), None) if k.len() == 1 => cnt_key += 1, (None, Some(pfx)) if pfx.len() == 1 => cnt_pfx += 1, _ => unreachable!("logic error"), - }; + } if next.is_none() { break; } diff --git a/src/model/helper/locked.rs b/src/model/helper/locked.rs index 62d8505e..a1ad5b2b 100644 --- a/src/model/helper/locked.rs +++ b/src/model/helper/locked.rs @@ -37,7 +37,7 @@ pub struct LockedHelper<'a>( impl<'a> Drop for LockedHelper<'a> { fn drop(&mut self) { // make it explicit that the mutexguard lives until here - drop(self.1.take()) + drop(self.1.take()); } } diff --git a/src/model/k2v/seen.rs b/src/model/k2v/seen.rs index ad38c6ae..9616fcb4 100644 --- a/src/model/k2v/seen.rs +++ b/src/model/k2v/seen.rs @@ -71,7 +71,7 @@ impl RangeSeenMarker { pub fn canonicalize(&mut self) { let self_vc = &self.vector_clock; - self.items.retain(|_sk, vc| vclock_gt(vc, self_vc)) + self.items.retain(|_sk, vc| vclock_gt(vc, self_vc)); } pub fn encode(&mut self) -> Result { diff --git a/src/net/client.rs b/src/net/client.rs index bdb1e6c4..5834b4ab 100644 --- a/src/net/client.rs +++ b/src/net/client.rs @@ -277,7 +277,7 @@ impl Stream for CancelOnDropStream { let res = this.stream.poll_next(cx); if matches!(res, Poll::Ready(None)) { if let Some(c) = this.cancel.take() { - std::mem::forget(c) + std::mem::forget(c); } } res diff --git a/src/net/error.rs b/src/net/error.rs index f67794ed..7010d51e 100644 --- a/src/net/error.rs +++ b/src/net/error.rs @@ -72,7 +72,7 @@ where fn log_err(self, msg: &'static str) { if let Err(e) = self { error!("Error: {}: {}", msg, Into::::into(e)); - }; + } } } diff --git a/src/net/netapp.rs b/src/net/netapp.rs index 5ffc2d7f..14d0b53b 100644 --- a/src/net/netapp.rs +++ b/src/net/netapp.rs @@ -180,7 +180,7 @@ impl NetApp { .is_some() { panic!("Redefining endpoint: {}", path); - }; + } endpoint } diff --git a/src/net/recv.rs b/src/net/recv.rs index b7acb612..1a00ecf6 100644 --- a/src/net/recv.rs +++ b/src/net/recv.rs @@ -70,7 +70,7 @@ pub(crate) trait RecvLoop: Sync + 'static { Ok(_) => (), Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break, Err(e) => return Err(e.into()), - }; + } let id = RequestID::from_be_bytes(header_id); let mut header_size = [0u8; ChunkLength::BITS as usize / 8]; diff --git a/src/net/send.rs b/src/net/send.rs index 16248f66..cf040888 100644 --- a/src/net/send.rs +++ b/src/net/send.rs @@ -319,7 +319,7 @@ pub(crate) trait SendLoop: Sync { order_tag, data: ByteStreamReader::new(data), sent: 0, - }) + }); } Some(SendItem::Cancel(id)) => { trace!("send_loop({}): cancelling {}", debug_name, id); @@ -332,7 +332,7 @@ pub(crate) trait SendLoop: Sync { None => { msg_recv = None; } - }; + } } (id, data) = send_fut => { trace!( diff --git a/src/net/test.rs b/src/net/test.rs index 3cf446bd..bb45741b 100644 --- a/src/net/test.rs +++ b/src/net/test.rs @@ -15,12 +15,12 @@ use crate::NodeID; #[tokio::test(flavor = "current_thread")] async fn test_with_basic_scheduler() { pretty_env_logger::init(); - run_test(19980).await + run_test(19980).await; } #[tokio::test(flavor = "multi_thread", worker_threads = 4)] async fn test_with_threaded_scheduler() { - run_test(19990).await + run_test(19990).await; } async fn run_test(port_base: u16) { diff --git a/src/rpc/consul.rs b/src/rpc/consul.rs index 9391e220..7aac4277 100644 --- a/src/rpc/consul.rs +++ b/src/rpc/consul.rs @@ -118,7 +118,7 @@ impl ConsulDiscovery { builder = builder.default_headers(headers); } } - }; + } let client: reqwest::Client = builder.build()?; diff --git a/src/rpc/kubernetes.rs b/src/rpc/kubernetes.rs index 85254bb5..f15afae0 100644 --- a/src/rpc/kubernetes.rs +++ b/src/rpc/kubernetes.rs @@ -66,7 +66,7 @@ pub async fn get_kubernetes_nodes( .and_then(|k| NodeID::from_slice(&k[..])); if let Some(pubkey) = pubkey { - ret.push((*pubkey, SocketAddr::new(node.spec.address, node.spec.port))) + ret.push((*pubkey, SocketAddr::new(node.spec.address, node.spec.port))); } } @@ -108,7 +108,7 @@ pub async fn publish_kubernetes_node( .await?; } else { nodes.create(&PostParams::default(), &node).await?; - }; + } Ok(()) } diff --git a/src/rpc/layout/version.rs b/src/rpc/layout/version.rs index 06a1392c..be2f98f3 100644 --- a/src/rpc/layout/version.rs +++ b/src/rpc/layout/version.rs @@ -85,7 +85,7 @@ impl LayoutVersion { let mut count = 0; for nod in self.ring_assignment_data.iter() { if i as u8 == *nod { - count += 1 + count += 1; } } return Ok(count); diff --git a/src/rpc/rpc_helper.rs b/src/rpc/rpc_helper.rs index d7ec5242..0805c1cb 100644 --- a/src/rpc/rpc_helper.rs +++ b/src/rpc/rpc_helper.rs @@ -374,7 +374,7 @@ impl RpcHelper { // reach quorum, start some new requests. while send_all_at_once || successes.len() + resp_stream.len() < quorum { if let Some(fut) = requests.next() { - resp_stream.push(fut) + resp_stream.push(fut); } else { break; } @@ -582,7 +582,7 @@ impl RpcHelper { let mut vernodes = vec![]; for ver in layout.versions()?.iter() { let nodes = ver.nodes_of(position); - vernodes.push(rpc_helper.request_order(current_layout, nodes)) + vernodes.push(rpc_helper.request_order(current_layout, nodes)); } let mut ret = if vernodes.len() == 1 { diff --git a/src/rpc/system.rs b/src/rpc/system.rs index 06633b78..0cd301ff 100644 --- a/src/rpc/system.rs +++ b/src/rpc/system.rs @@ -481,7 +481,7 @@ impl System { .iter() .filter(|(_, _, v)| matches!(v, NodeRoleV(Some(r)) if r.capacity.is_some())) .map(|(n, _, _)| *n), - ) + ); } let storage_nodes_ok = storage_nodes.iter().filter(|x| node_up(x)).count(); @@ -682,7 +682,7 @@ impl System { // Add peer list from list stored on disk if let Ok(peers) = self.persist_peer_list.load_async().await { - ping_list.extend(peers.0.iter().map(|(id, addr)| ((*id).into(), *addr))) + ping_list.extend(peers.0.iter().map(|(id, addr)| ((*id).into(), *addr))); } // Fetch peer list from Consul @@ -705,9 +705,9 @@ impl System { match create_kubernetes_crd().await { Ok(()) => (), Err(e) => { - error!("Failed to create kubernetes custom resource: {}", e) + error!("Failed to create kubernetes custom resource: {}", e); } - }; + } } match get_kubernetes_nodes(k).await { diff --git a/src/rpc/system_metrics.rs b/src/rpc/system_metrics.rs index 23957399..3d6c6e8b 100644 --- a/src/rpc/system_metrics.rs +++ b/src/rpc/system_metrics.rs @@ -60,7 +60,7 @@ impl SystemMetrics { KeyValue::new("rustversion", garage_util::version::rust_version()), KeyValue::new("version", garage_util::version::garage_version()), ], - ) + ); }) .with_description("Garage build info") .init(), @@ -68,7 +68,7 @@ impl SystemMetrics { let replication_factor = system.replication_factor; meter .u64_value_observer("garage_replication_factor", move |observer| { - observer.observe(usize::from(replication_factor) as u64, &[]) + observer.observe(usize::from(replication_factor) as u64, &[]); }) .with_description("Garage replication factor setting") .init() diff --git a/src/web/web_server.rs b/src/web/web_server.rs index f50e4ca7..2d0cac2d 100644 --- a/src/web/web_server.rs +++ b/src/web/web_server.rs @@ -106,7 +106,7 @@ impl WebServer { } UnixOrTCPSocketAddress::UnixSocket(ref path) => { if path.exists() { - fs::remove_file(path)? + fs::remove_file(path)?; } let listener = UnixListener::bind(path)?; @@ -684,10 +684,10 @@ fn compute_redirect_target(redirect: &bucket_table::Redirect, suffix: Option<&st if let Some(replace_key_prefix) = &redirect.replace_key_prefix { res.push_str(replace_key_prefix); if let Some(suffix) = suffix { - res.push_str(suffix) + res.push_str(suffix); } } else if let Some(replace_key) = &redirect.replace_key { - res.push_str(replace_key) + res.push_str(replace_key); } res } From bbb62dfa85486a1e710edf2cfafb8295e6bd1594 Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Tue, 27 Jan 2026 22:06:26 +0100 Subject: [PATCH 4/8] refactor: use `u64::midpoint` instead of manual implementation warning: manual implementation of `midpoint` which can overflow help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#manual_midpoint --- Cargo.toml | 1 + src/rpc/layout/version.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6bd3d32a..53e14412 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -183,5 +183,6 @@ strip = "debuginfo" [workspace.lints.clippy] # pedantic lints configuration doc_markdown = "warn" +manual_midpoint = "warn" semicolon_if_nothing_returned = "warn" unnecessary_semicolon = "warn" diff --git a/src/rpc/layout/version.rs b/src/rpc/layout/version.rs index be2f98f3..dda48ea3 100644 --- a/src/rpc/layout/version.rs +++ b/src/rpc/layout/version.rs @@ -527,16 +527,16 @@ impl LayoutVersion { let mut s_up = self.get_total_capacity(); while s_down + 1 < s_up { g = self.generate_flow_graph( - (s_down + s_up) / 2, + u64::midpoint(s_down, s_up), zone_to_id, &empty_set, zone_redundancy, )?; g.compute_maximal_flow()?; if g.get_flow_value()? < (NB_PARTITIONS * self.replication_factor) as i64 { - s_up = (s_down + s_up) / 2; + s_up = u64::midpoint(s_down, s_up); } else { - s_down = (s_down + s_up) / 2; + s_down = u64::midpoint(s_down, s_up); } } From f6414210facf079b1965aa6593bae9a4ddab323b Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Wed, 28 Jan 2026 11:07:46 +0100 Subject: [PATCH 5/8] refactor: rework bucket value get, relateted to or_func_call this avoid bucket_website_config value compute if not needed --- src/garage/cli/remote/bucket.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/garage/cli/remote/bucket.rs b/src/garage/cli/remote/bucket.rs index 692ded63..aa5fa5ea 100644 --- a/src/garage/cli/remote/bucket.rs +++ b/src/garage/cli/remote/bucket.rs @@ -295,13 +295,20 @@ impl Cli { )); } + // Destructure becket info to allow separate use of `id` and `website_config` + let GetBucketInfoResponse { + id: bucket_id, + website_config: bucket_website_config, + .. + } = bucket; + let wa = if opt.allow { UpdateBucketWebsiteAccess { enabled: true, index_document: Some(opt.index_document.clone()), error_document: opt .error_document - .or(bucket.website_config.and_then(|x| x.error_document.clone())), + .or_else(|| bucket_website_config.and_then(|x| x.error_document.clone())), } } else { UpdateBucketWebsiteAccess { @@ -313,7 +320,7 @@ impl Cli { let res = self .api_request(UpdateBucketRequest { - id: bucket.id, + id: bucket_id, body: UpdateBucketRequestBody { website_access: Some(wa), quotas: None, From b060a7e0f1ac55f9baf9a312d87a7e0696b67261 Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Wed, 28 Jan 2026 11:07:24 +0100 Subject: [PATCH 6/8] fix: remove func call from alternative value. this avoid useless allocation or non-trivial work, if the default value is not needed/used. add a line in Cargo.toml to easly enable or_fun_call lint help: https://rust-lang.github.io/rust-clippy/master/index.html?search=or_fun_call --- Cargo.toml | 3 +++ src/api/k2v/router.rs | 2 +- src/api/s3/multipart.rs | 2 +- src/api/s3/router.rs | 2 +- src/garage/cli/remote/admin_token.rs | 16 +++++++++------- src/garage/cli/remote/key.rs | 12 +++++++----- src/model/s3/lifecycle_worker.rs | 6 +++++- src/rpc/layout/helper.rs | 4 ++-- 8 files changed, 29 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 53e14412..e3dd1ccd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -186,3 +186,6 @@ doc_markdown = "warn" manual_midpoint = "warn" semicolon_if_nothing_returned = "warn" unnecessary_semicolon = "warn" + +# nursery lints configuration +# or_fun_call = "warn" # enable it to help detect non trivial code used in `_or` method diff --git a/src/api/k2v/router.rs b/src/api/k2v/router.rs index 4e50bfa6..642b002b 100644 --- a/src/api/k2v/router.rs +++ b/src/api/k2v/router.rs @@ -62,7 +62,7 @@ impl Endpoint { let (bucket, partition_key) = path .split_once('/') .map(|(b, p)| (b.to_owned(), p.trim_start_matches('/'))) - .unwrap_or((path.to_owned(), "")); + .unwrap_or_else(|| (path.to_owned(), "")); if bucket.is_empty() { return Err(Error::bad_request("Missing bucket name")); diff --git a/src/api/s3/multipart.rs b/src/api/s3/multipart.rs index 5e56408f..c5eea912 100644 --- a/src/api/s3/multipart.rs +++ b/src/api/s3/multipart.rs @@ -494,7 +494,7 @@ pub async fn handle_complete_multipart_upload( .root_domain .as_ref() .map(|rd| s3_xml::Value(format!("https://{}.{}/{}", bucket_name, rd, key))) - .or(Some(s3_xml::Value(format!("/{}/{}", bucket_name, key)))), + .or_else(|| Some(s3_xml::Value(format!("/{}/{}", bucket_name, key)))), bucket: s3_xml::Value(bucket_name.to_string()), key: s3_xml::Value(key), etag: s3_xml::Value(format!("\"{}\"", etag)), diff --git a/src/api/s3/router.rs b/src/api/s3/router.rs index 3f2d9208..69c95876 100644 --- a/src/api/s3/router.rs +++ b/src/api/s3/router.rs @@ -330,7 +330,7 @@ impl Endpoint { } else { path.split_once('/') .map(|(b, p)| (b.to_owned(), p.trim_start_matches('/'))) - .unwrap_or((path.to_owned(), "")) + .unwrap_or_else(|| (path.to_owned(), "")) }; if *req.method() == Method::OPTIONS { diff --git a/src/garage/cli/remote/admin_token.rs b/src/garage/cli/remote/admin_token.rs index 5a0b0595..144c11c7 100644 --- a/src/garage/cli/remote/admin_token.rs +++ b/src/garage/cli/remote/admin_token.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use format_table::format_table; use chrono::Local; @@ -42,18 +44,18 @@ impl Cli { table_list_abbr(&tok.scope) }; let exp = if tok.expired { - "expired".to_string() + Cow::Borrowed("expired") } else { tok.expiration - .map(|x| x.with_timezone(&Local).to_string()) - .unwrap_or("never".into()) + .map(|x| x.with_timezone(&Local).to_string().into()) + .unwrap_or(Cow::Borrowed("never")) }; table.push(format!( "{}\t{}\t{}\t{}\t{}", tok.id.as_deref().unwrap_or("-"), tok.created - .map(|x| x.with_timezone(&Local).date_naive().to_string()) - .unwrap_or("-".into()), + .map(|x| x.with_timezone(&Local).date_naive().to_string().into()) + .unwrap_or(Cow::Borrowed("-")), tok.name, exp, scope, @@ -236,8 +238,8 @@ fn print_token_info(token: &GetAdminTokenInfoResponse) { "Expiration:\t{}", token .expiration - .map(|x| x.with_timezone(&Local).to_string()) - .unwrap_or("never".into()) + .map(|x| x.with_timezone(&Local).to_string().into()) + .unwrap_or(Cow::Borrowed("never")) ), String::new(), ]; diff --git a/src/garage/cli/remote/key.rs b/src/garage/cli/remote/key.rs index 657607ea..68de358f 100644 --- a/src/garage/cli/remote/key.rs +++ b/src/garage/cli/remote/key.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use format_table::format_table; use chrono::Local; @@ -33,11 +35,11 @@ impl Cli { let mut table = vec!["ID\tCreated\tName\tExpiration".to_string()]; for key in keys.0.iter() { let exp = if key.expired { - "expired".to_string() + Cow::from("expired") } else { key.expiration - .map(|x| x.with_timezone(&Local).to_string()) - .unwrap_or("never".into()) + .map(|x| x.with_timezone(&Local).to_string().into()) + .unwrap_or(Cow::Borrowed("never")) }; table.push(format!( "{}\t{}\t{}\t{}", @@ -288,8 +290,8 @@ fn print_key_info(key: &GetKeyInfoResponse) { format!( "Expiration:\t{}", key.expiration - .map(|x| x.with_timezone(&Local).to_string()) - .unwrap_or("never".into()) + .map(|x| x.with_timezone(&Local).to_string().into()) + .unwrap_or(Cow::Borrowed("never")) ), String::new(), format!("Can create buckets:\t{}", key.permissions.create_bucket), diff --git a/src/model/s3/lifecycle_worker.rs b/src/model/s3/lifecycle_worker.rs index a400b5bf..f014337f 100644 --- a/src/model/s3/lifecycle_worker.rs +++ b/src/model/s3/lifecycle_worker.rs @@ -65,7 +65,11 @@ pub fn register_bg_vars( vars: &mut vars::BgVars, ) { vars.register_ro(persister, "lifecycle-last-completed", |p| { - p.get_with(|x| x.last_completed.clone().unwrap_or("never".to_string())) + p.get_with(|x| { + x.last_completed + .clone() + .unwrap_or_else(|| "never".to_string()) + }) }); } diff --git a/src/rpc/layout/helper.rs b/src/rpc/layout/helper.rs index 2fa6f913..89ffe2ad 100644 --- a/src/rpc/layout/helper.rs +++ b/src/rpc/layout/helper.rs @@ -169,7 +169,7 @@ impl LayoutHelper { Ok(versions .iter() .find(|x| x.version == sync_min) - .or(versions.last()) + .or_else(|| versions.last()) .unwrap()) } @@ -271,7 +271,7 @@ impl LayoutHelper { .map(|x| x.load(Ordering::Relaxed) == 0) .unwrap_or(true) }) - .unwrap_or(self.inner().current().version); + .unwrap_or_else(|| self.inner().current().version); let changed = self.update(|layout| { layout .update_trackers From 83f8bdbacd8d878ea631ee344a4b87a83c7be066 Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Mon, 2 Feb 2026 17:34:32 +0100 Subject: [PATCH 7/8] refactor: remove unnecessarily wrap value into a Result this simplify code and remove some unwrap. warning: this function's return value is unnecessarily wrapped by `Result` help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#unnecessary_wraps --- Cargo.toml | 1 + src/api/s3/get.rs | 16 ++++++++-------- src/api/s3/list.rs | 20 +++++++++----------- src/garage/tracing_setup.rs | 1 + src/rpc/layout/test.rs | 19 +++++++++---------- src/rpc/layout/version.rs | 10 ++++------ src/util/config.rs | 1 + 7 files changed, 33 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e3dd1ccd..44db8c99 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -186,6 +186,7 @@ doc_markdown = "warn" manual_midpoint = "warn" semicolon_if_nothing_returned = "warn" unnecessary_semicolon = "warn" +unnecessary_wraps = "warn" # nursery lints configuration # or_fun_call = "warn" # enable it to help detect non trivial code used in `_or` method diff --git a/src/api/s3/get.rs b/src/api/s3/get.rs index ec641f25..02500bf4 100644 --- a/src/api/s3/get.rs +++ b/src/api/s3/get.rs @@ -126,7 +126,7 @@ fn handle_http_precondition( ) -> Result>, Error> { let precondition_headers = PreconditionHeaders::parse(req)?; - if let Some(status_code) = precondition_headers.check(version, &version_meta.etag)? { + if let Some(status_code) = precondition_headers.check(version, &version_meta.etag) { let mut response = object_headers( version, version_meta, @@ -877,7 +877,7 @@ impl PreconditionHeaders { }) } - fn check(&self, v: &ObjectVersion, etag: &str) -> Result, Error> { + fn check(&self, v: &ObjectVersion, etag: &str) -> Option { // we store date with ms precision, but headers are precise to the second: truncate // the timestamp to handle the same-second edge case let v_date = UNIX_EPOCH + Duration::from_secs(v.timestamp / 1000); @@ -887,32 +887,32 @@ impl PreconditionHeaders { if let Some(im) = &self.if_match { // Step 1: if-match is present if !im.iter().any(|x| x == etag || x == "*") { - return Ok(Some(StatusCode::PRECONDITION_FAILED)); + return Some(StatusCode::PRECONDITION_FAILED); } } else if let Some(ius) = &self.if_unmodified_since { // Step 2: if-unmodified-since is present, and if-match is absent if v_date > *ius { - return Ok(Some(StatusCode::PRECONDITION_FAILED)); + return Some(StatusCode::PRECONDITION_FAILED); } } if let Some(inm) = &self.if_none_match { // Step 3: if-none-match is present if inm.iter().any(|x| x == etag || x == "*") { - return Ok(Some(StatusCode::NOT_MODIFIED)); + return Some(StatusCode::NOT_MODIFIED); } } else if let Some(ims) = &self.if_modified_since { // Step 4: if-modified-since is present, and if-none-match is absent if v_date <= *ims { - return Ok(Some(StatusCode::NOT_MODIFIED)); + return Some(StatusCode::NOT_MODIFIED); } } - Ok(None) + None } pub(crate) fn check_copy_source(&self, v: &ObjectVersion, etag: &str) -> Result<(), Error> { - match self.check(v, etag)? { + match self.check(v, etag) { Some(_) => Err(Error::PreconditionFailed), None => Ok(()), } diff --git a/src/api/s3/list.rs b/src/api/s3/list.rs index 67d9922e..9c2bc116 100644 --- a/src/api/s3/list.rs +++ b/src/api/s3/list.rs @@ -296,7 +296,7 @@ pub async fn handle_list_parts( }, ); - let (info, next) = fetch_part_info(query, &mpu)?; + let (info, next) = fetch_part_info(query, &mpu); let result = s3_xml::ListPartsResult { xmlns: (), @@ -526,7 +526,7 @@ where fn fetch_part_info<'a>( query: &ListPartsQuery, mpu: &'a MultipartUpload, -) -> Result<(Vec>, Option), Error> { +) -> (Vec>, Option) { assert!((1..=1000).contains(&query.max_parts)); // see s3/api_server.rs // Parse multipart upload part list, removing parts not yet finished @@ -565,10 +565,10 @@ fn fetch_part_info<'a>( if parts.len() > query.max_parts as usize { parts.truncate(query.max_parts as usize); let pagination = Some(parts.last().unwrap().part_number); - return Ok((parts, pagination)); + return (parts, pagination); } - Ok((parts, None)) + (parts, None) } /* @@ -1255,7 +1255,7 @@ mod tests { } #[test] - fn test_fetch_part_info() -> Result<(), Error> { + fn test_fetch_part_info() { let mut query = ListPartsQuery { bucket_name: "a".to_string(), key: "a".to_string(), @@ -1267,7 +1267,7 @@ mod tests { let mpu = mpu(); // Start from the beginning but with limited size to trigger pagination - let (info, pagination) = fetch_part_info(&query, &mpu)?; + let (info, pagination) = fetch_part_info(&query, &mpu); assert_eq!(pagination.unwrap(), 3); assert_eq!( info, @@ -1291,7 +1291,7 @@ mod tests { // Use previous pagination to make a new request query.part_number_marker = Some(pagination.unwrap()); - let (info, pagination) = fetch_part_info(&query, &mpu)?; + let (info, pagination) = fetch_part_info(&query, &mpu); assert!(pagination.is_none()); assert_eq!( info, @@ -1315,14 +1315,14 @@ mod tests { // Trying to access a part that is way larger than registered ones query.part_number_marker = Some(9999); - let (info, pagination) = fetch_part_info(&query, &mpu)?; + let (info, pagination) = fetch_part_info(&query, &mpu); assert!(pagination.is_none()); assert_eq!(info, vec![]); // Try without any limitation query.max_parts = 1000; query.part_number_marker = None; - let (info, pagination) = fetch_part_info(&query, &mpu)?; + let (info, pagination) = fetch_part_info(&query, &mpu); assert!(pagination.is_none()); assert_eq!( info, @@ -1357,7 +1357,5 @@ mod tests { }, ] ); - - Ok(()) } } diff --git a/src/garage/tracing_setup.rs b/src/garage/tracing_setup.rs index d5568c82..8cc591ec 100644 --- a/src/garage/tracing_setup.rs +++ b/src/garage/tracing_setup.rs @@ -5,6 +5,7 @@ mod telemetry { use garage_util::data::Uuid; use garage_util::error::Error; + #[expect(clippy::unnecessary_wraps)] pub fn init_tracing(_: &str, _: Uuid) -> Result<(), Error> { error!("Garage was built without OTLP exporter, admin.trace_sink is ignored."); Ok(()) diff --git a/src/rpc/layout/test.rs b/src/rpc/layout/test.rs index e6505d87..aa146dfd 100644 --- a/src/rpc/layout/test.rs +++ b/src/rpc/layout/test.rs @@ -2,7 +2,6 @@ use std::cmp::min; use std::collections::HashMap; use garage_util::crdt::Crdt; -use garage_util::error::*; use crate::layout::*; use crate::replication_mode::ReplicationFactor; @@ -21,14 +20,14 @@ use crate::replication_mode::ReplicationFactor; // number of tokens by zone : (A, 4), (B,1), (C,4), (D, 4), (E, 2) // With these parameters, the naive algo fails, whereas there is a solution: // (A,A,C,D,E) , (A,B,C,D,D) (A,C,C,D,E) -fn check_against_naive(cl: &LayoutVersion) -> Result { +fn check_against_naive(cl: &LayoutVersion) -> bool { let over_size = cl.partition_size + 1; let mut zone_token = HashMap::::new(); - let (zones, zone_to_id) = cl.generate_nongateway_zone_ids()?; + let (zones, zone_to_id) = cl.generate_nongateway_zone_ids(); if zones.is_empty() { - return Ok(false); + return false; } for z in zones.iter() { @@ -66,7 +65,7 @@ fn check_against_naive(cl: &LayoutVersion) -> Result { { curr_zone += 1; if curr_zone >= zones.len() { - return Ok(true); + return true; } } id_zone_token[curr_zone] -= 1; @@ -77,7 +76,7 @@ fn check_against_naive(cl: &LayoutVersion) -> Result { } } - Ok(false) + false } fn show_msg(msg: &Message) { @@ -127,7 +126,7 @@ fn test_assignment() { let (mut cl, msg) = cl.apply_staged_changes(v + 1).unwrap(); show_msg(&msg); assert_eq!(cl.check(), Ok(())); - assert!(check_against_naive(cl.current()).unwrap()); + assert!(check_against_naive(cl.current())); node_capacity_vec = vec![4000, 1000, 1000, 3000, 1000, 1000, 2000, 10000, 2000]; node_zone_vec = vec!["A", "B", "C", "C", "C", "B", "G", "H", "I"]; @@ -136,7 +135,7 @@ fn test_assignment() { let (mut cl, msg) = cl.apply_staged_changes(v + 1).unwrap(); show_msg(&msg); assert_eq!(cl.check(), Ok(())); - assert!(check_against_naive(cl.current()).unwrap()); + assert!(check_against_naive(cl.current())); node_capacity_vec = vec![4000, 1000, 2000, 7000, 1000, 1000, 2000, 10000, 2000]; update_layout(&mut cl, &node_capacity_vec, &node_zone_vec, 3); @@ -144,7 +143,7 @@ fn test_assignment() { let (mut cl, msg) = cl.apply_staged_changes(v + 1).unwrap(); show_msg(&msg); assert_eq!(cl.check(), Ok(())); - assert!(check_against_naive(cl.current()).unwrap()); + assert!(check_against_naive(cl.current())); node_capacity_vec = vec![ 4000000, 4000000, 2000000, 7000000, 1000000, 9000000, 2000000, 10000, 2000000, @@ -154,5 +153,5 @@ fn test_assignment() { let (cl, msg) = cl.apply_staged_changes(v + 1).unwrap(); show_msg(&msg); assert_eq!(cl.check(), Ok(())); - assert!(check_against_naive(cl.current()).unwrap()); + assert!(check_against_naive(cl.current())); } diff --git a/src/rpc/layout/version.rs b/src/rpc/layout/version.rs index dda48ea3..18728e63 100644 --- a/src/rpc/layout/version.rs +++ b/src/rpc/layout/version.rs @@ -271,7 +271,7 @@ impl LayoutVersion { // Check that the partition size stored is the one computed by the asignation // algorithm. let cl2 = self.clone(); - let (_, zone_to_id) = cl2.generate_nongateway_zone_ids().unwrap(); + let (_, zone_to_id) = cl2.generate_nongateway_zone_ids(); match cl2.compute_optimal_partition_size(&zone_to_id, zone_redundancy) { Ok(s) if s != self.partition_size => { return Err(format!( @@ -330,7 +330,7 @@ impl LayoutVersion { // We generate for once numerical ids for the zones of non gateway nodes, // to use them as indices in the flow graphs. - let (id_to_zone, zone_to_id) = self.generate_nongateway_zone_ids()?; + let (id_to_zone, zone_to_id) = self.generate_nongateway_zone_ids(); if self.nongateway_nodes().len() < self.replication_factor { return Err(Error::Message(format!( @@ -489,9 +489,7 @@ impl LayoutVersion { /// This function generates ids for the zone of the nodes appearing in /// `self.node_id_vec`. - pub(crate) fn generate_nongateway_zone_ids( - &self, - ) -> Result<(Vec, HashMap), Error> { + pub(crate) fn generate_nongateway_zone_ids(&self) -> (Vec, HashMap) { let mut id_to_zone = Vec::::new(); let mut zone_to_id = HashMap::::new(); @@ -502,7 +500,7 @@ impl LayoutVersion { id_to_zone.push(r.zone.clone()); } } - Ok((id_to_zone, zone_to_id)) + (id_to_zone, zone_to_id) } /// This function computes by dichotomy the largest realizable partition size, given diff --git a/src/util/config.rs b/src/util/config.rs index c4013fb6..aafc21b5 100644 --- a/src/util/config.rs +++ b/src/util/config.rs @@ -305,6 +305,7 @@ fn default_consistency_mode() -> String { "consistent".into() } +#[expect(clippy::unnecessary_wraps)] fn default_compression() -> Option { Some(1) } From 9b3e4716bf40ee2726d04bf2a514df5f0b1befdb Mon Sep 17 00:00:00 2001 From: Gwen Lg Date: Mon, 2 Feb 2026 18:37:07 +0100 Subject: [PATCH 8/8] refactor: rework uri_encode to limit allocation add add some related tests. catched from clippy lint `format_collect` message: use of `format!` to build up a string from an iterator --> src/api/common/encoding.rs:12:17 | 12 | let value = format!("{}", c) | _____________________________^ 13 | | .bytes() 14 | | .map(|b| format!("%{:02X}", b)) 15 | | .collect::(); | |________________________________________^ | help: call `fold` instead --> src/api/common/encoding.rs:14:7 | 14 | .map(|b| format!("%{:02X}", b)) | ^^^ help: ... and use the `write!` macro here --> src/api/common/encoding.rs:14:15 | 14 | .map(|b| format!("%{:02X}", b)) | ^^^^^^^^^^^^^^^^^^^^^ = note: this can be written more efficiently by appending to a `String` directly = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.93.0/index.html#format_collect --- Cargo.toml | 1 + src/api/common/encoding.rs | 98 +++++++++++++++++++++++++++++++++++--- 2 files changed, 93 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44db8c99..5aac1826 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -183,6 +183,7 @@ strip = "debuginfo" [workspace.lints.clippy] # pedantic lints configuration doc_markdown = "warn" +format_collect = "warn" manual_midpoint = "warn" semicolon_if_nothing_returned = "warn" unnecessary_semicolon = "warn" diff --git a/src/api/common/encoding.rs b/src/api/common/encoding.rs index e286a784..4ff33ecc 100644 --- a/src/api/common/encoding.rs +++ b/src/api/common/encoding.rs @@ -1,5 +1,7 @@ //! Module containing various helpers for encoding +use std::fmt::Write as _; + /// Encode &str for use in a URI pub fn uri_encode(string: &str, encode_slash: bool) -> String { let mut result = String::with_capacity(string.len() * 2); @@ -9,14 +11,98 @@ pub fn uri_encode(string: &str, encode_slash: bool) -> String { '/' if encode_slash => result.push_str("%2F"), '/' if !encode_slash => result.push('/'), _ => { - result.push_str( - &format!("{}", c) - .bytes() - .map(|b| format!("%{:02X}", b)) - .collect::(), - ); + let mut buf = [0_u8; 4]; + let str = c.encode_utf8(&mut buf); + for b in str.bytes() { + write!(&mut result, "%{:02X}", b).unwrap(); + } } } } result } + +#[cfg(test)] +mod tests { + use crate::encoding::uri_encode; + + #[test] + fn test_uri_encode() { + let url1_encoded = uri_encode( + "https://garagehq.deuxfleurs.fr/documentation/reference-manual/features/", + true, + ); + assert_eq!( + &url1_encoded, + "https%3A%2F%2Fgaragehq.deuxfleurs.fr%2Fdocumentation%2Freference-manual%2Ffeatures%2F" + ); + + let url2_encoded = uri_encode( + "https://garagehq.deuxfleurs.fr/blog/2025-06-garage-v2/", + true, + ); + assert_eq!( + &url2_encoded, + "https%3A%2F%2Fgaragehq.deuxfleurs.fr%2Fblog%2F2025-06-garage-v2%2F" + ); + + let url3_encoded = uri_encode( + "https://garagehq.deuxfleurs.fr/blog/2025-06-hé_les_gens/", + true, + ); + assert_eq!( + &url3_encoded, + "https%3A%2F%2Fgaragehq.deuxfleurs.fr%2Fblog%2F2025-06-h%C3%A9_les_gens%2F" + ); + + let url4_encoded = uri_encode("/home/local user/Documents/personnel/à_blog.md", true); + assert_eq!( + &url4_encoded, + "%2Fhome%2Flocal%20user%2FDocuments%2Fpersonnel%2F%C3%A0_blog.md" + ); + } + + #[test] + fn test_uri_encode_without_slash() { + let url1_encoded = uri_encode( + "https://garagehq.deuxfleurs.fr/documentation/reference-manual/features/", + false, + ); + assert_eq!( + &url1_encoded, + "https%3A//garagehq.deuxfleurs.fr/documentation/reference-manual/features/" + ); + + let url2_encoded = uri_encode( + "https://garagehq.deuxfleurs.fr/blog/2025-06-garage-v2/", + false, + ); + assert_eq!( + &url2_encoded, + "https%3A//garagehq.deuxfleurs.fr/blog/2025-06-garage-v2/" + ); + + let url3_encoded = uri_encode( + "https://garagehq.deuxfleurs.fr/blog/2025-06-hé_les_gens/", + false, + ); + assert_eq!( + &url3_encoded, + "https%3A//garagehq.deuxfleurs.fr/blog/2025-06-h%C3%A9_les_gens/" + ); + let url4_encoded = uri_encode("/home/local user/Documents/personnel/à_blog.md", false); + assert_eq!( + &url4_encoded, + "/home/local%20user/Documents/personnel/%C3%A0_blog.md" + ); + } + + #[test] + fn test_uri_encode_most_than_double_size() { + let url_encoded = uri_encode("/home/ùàé ç/çaèù/à_êô.md", true); + assert_eq!( + &url_encoded, + "%2Fhome%2F%C3%B9%C3%A0%C3%A9%20%C3%A7%2F%C3%A7a%C3%A8%C3%B9%2F%C3%A0_%C3%AA%C3%B4.md" + ); + } +}