Function names updated to reflect AWS names. Updated docs (#150)

* updated inline doc

* updated inline doc

* API naming conform AWS

* fixed clippy issues

* fixed minor API naming issues
This commit is contained in:
Henk-Jan Lebbink 2025-05-10 00:53:44 +02:00 committed by GitHub
parent 1869cfeba7
commit 20d8654e34
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
192 changed files with 2033 additions and 1593 deletions

View File

@ -19,11 +19,12 @@ jobs:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: Build - name: Build
run: | run: |
cargo --version
cargo fmt --all -- --check cargo fmt --all -- --check
cargo clippy --all-targets --all-features cargo clippy --all-targets --all-features
cargo build --bins --examples --tests --benches --verbose cargo build --bins --examples --tests --benches --verbose
- name: Run tests S3 - name: Run tests
run: | run: |
./tests/start-server.sh ./tests/start-server.sh
export SERVER_ENDPOINT=localhost:9000 export SERVER_ENDPOINT=localhost:9000

View File

@ -18,7 +18,7 @@ mod bench_bucket_lifecycle;
mod bench_bucket_notification; mod bench_bucket_notification;
mod bench_bucket_policy; mod bench_bucket_policy;
mod bench_bucket_replication; mod bench_bucket_replication;
mod bench_bucket_tags; mod bench_bucket_tagging;
mod bench_bucket_versioning; mod bench_bucket_versioning;
mod bench_list_bucket; mod bench_list_bucket;
mod bench_object_append; mod bench_object_append;
@ -27,7 +27,7 @@ mod bench_object_legal_hold;
mod bench_object_lock_config; mod bench_object_lock_config;
mod bench_object_put; mod bench_object_put;
mod bench_object_retention; mod bench_object_retention;
mod bench_object_tags; mod bench_object_tagging;
mod common_benches; mod common_benches;
use criterion::{Criterion, criterion_group, criterion_main}; use criterion::{Criterion, criterion_group, criterion_main};
@ -40,7 +40,7 @@ use crate::bench_bucket_notification::*;
use crate::bench_bucket_policy::*; use crate::bench_bucket_policy::*;
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::bench_bucket_replication::*; use crate::bench_bucket_replication::*;
use crate::bench_bucket_tags::*; use crate::bench_bucket_tagging::*;
use crate::bench_bucket_versioning::*; use crate::bench_bucket_versioning::*;
use crate::bench_list_bucket::*; use crate::bench_list_bucket::*;
#[allow(unused_imports)] #[allow(unused_imports)]
@ -51,7 +51,7 @@ use crate::bench_object_legal_hold::*;
use crate::bench_object_lock_config::*; use crate::bench_object_lock_config::*;
use crate::bench_object_put::bench_object_put; use crate::bench_object_put::bench_object_put;
use crate::bench_object_retention::*; use crate::bench_object_retention::*;
use crate::bench_object_tags::*; use crate::bench_object_tagging::*;
criterion_group!( criterion_group!(
name = benches; name = benches;
@ -63,27 +63,27 @@ criterion_group!(
.measurement_time(Duration::from_secs_f32(10.0)); .measurement_time(Duration::from_secs_f32(10.0));
targets = targets =
bench_bucket_exists, bench_bucket_exists,
bench_set_bucket_lifecycle, bench_put_bucket_lifecycle,
bench_get_bucket_lifecycle, bench_get_bucket_lifecycle,
bench_delete_bucket_lifecycle, bench_delete_bucket_lifecycle,
// //
//bench_set_bucket_notification, //A specified destination ARN does not exist or is not well-formed //bench_put_bucket_notification, //A specified destination ARN does not exist or is not well-formed
//bench_get_bucket_notification, //bench_get_bucket_notification,
//bench_delete_bucket_notification, //bench_delete_bucket_notification,
// //
bench_set_bucket_policy, bench_put_bucket_policy,
bench_get_bucket_policy, bench_get_bucket_policy,
bench_delete_bucket_policy, bench_delete_bucket_policy,
// //
//bench_set_bucket_replication, //TODO setup permissions to allow replication //bench_put_bucket_replication, //TODO setup permissions to allow replication
//bench_get_bucket_replication, //bench_get_bucket_replication,
//bench_delete_bucket_replication, //bench_delete_bucket_replication,
// //
bench_set_bucket_tags, bench_put_bucket_tagging,
bench_get_bucket_tags, bench_get_bucket_tagging,
bench_delete_bucket_tags, bench_delete_bucket_tagging,
// //
bench_set_bucket_versioning, bench_put_bucket_versioning,
bench_get_bucket_versioning, bench_get_bucket_versioning,
// //
bench_list_buckets, bench_list_buckets,
@ -91,19 +91,18 @@ criterion_group!(
bench_object_append, bench_object_append,
bench_object_put, bench_object_put,
// //
bench_enable_object_legal_hold, bench_put_object_legal_hold,
bench_disable_object_legal_hold, bench_get_object_legal_hold,
bench_is_object_legal_hold,
// //
bench_set_object_lock_config, bench_put_object_lock_config,
bench_get_object_lock_config, bench_get_object_lock_config,
bench_delete_object_lock_config, bench_delete_object_lock_config,
// //
bench_set_object_retention, bench_put_object_retention,
bench_get_object_retention, bench_get_object_retention,
// //
bench_set_object_tags, bench_put_object_tagging,
bench_get_object_tags bench_get_object_tagging
); );
criterion_main!(benches); criterion_main!(benches);

View File

@ -16,18 +16,18 @@
use crate::common_benches::{Ctx2, benchmark_s3_api}; use crate::common_benches::{Ctx2, benchmark_s3_api};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{DeleteBucketLifecycle, GetBucketLifecycle, SetBucketLifecycle}; use minio::s3::builders::{DeleteBucketLifecycle, GetBucketLifecycle, PutBucketLifecycle};
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use minio_common::example::create_bucket_lifecycle_config_examples; use minio_common::example::create_bucket_lifecycle_config_examples;
pub(crate) fn bench_set_bucket_lifecycle(criterion: &mut Criterion) { pub(crate) fn bench_put_bucket_lifecycle(criterion: &mut Criterion) {
benchmark_s3_api( benchmark_s3_api(
"set_bucket_lifecycle", "put_bucket_lifecycle",
criterion, criterion,
|| async { Ctx2::new().await }, || async { Ctx2::new().await },
|ctx| { |ctx| {
let config = create_bucket_lifecycle_config_examples(); let config = create_bucket_lifecycle_config_examples();
SetBucketLifecycle::new(ctx.client.clone(), ctx.bucket.clone()) PutBucketLifecycle::new(ctx.client.clone(), ctx.bucket.clone())
.life_cycle_config(config) .life_cycle_config(config)
}, },
) )
@ -40,7 +40,7 @@ pub(crate) fn bench_get_bucket_lifecycle(criterion: &mut Criterion) {
let ctx = Ctx2::new().await; let ctx = Ctx2::new().await;
let config = create_bucket_lifecycle_config_examples(); let config = create_bucket_lifecycle_config_examples();
ctx.client ctx.client
.set_bucket_lifecycle(&ctx.bucket) .put_bucket_lifecycle(&ctx.bucket)
.life_cycle_config(config) .life_cycle_config(config)
.send() .send()
.await .await

View File

@ -16,19 +16,19 @@
use crate::common_benches::{Ctx2, benchmark_s3_api}; use crate::common_benches::{Ctx2, benchmark_s3_api};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{DeleteBucketNotification, GetBucketNotification, SetBucketNotification}; use minio::s3::builders::{DeleteBucketNotification, GetBucketNotification, PutBucketNotification};
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use minio_common::example::create_bucket_notification_config_example; use minio_common::example::create_bucket_notification_config_example;
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn bench_set_bucket_notification(criterion: &mut Criterion) { pub(crate) fn bench_put_bucket_notification(criterion: &mut Criterion) {
benchmark_s3_api( benchmark_s3_api(
"set_bucket_notification", "put_bucket_notification",
criterion, criterion,
|| async { Ctx2::new().await }, || async { Ctx2::new().await },
|ctx| { |ctx| {
let config = create_bucket_notification_config_example(); let config = create_bucket_notification_config_example();
SetBucketNotification::new(ctx.client.clone(), ctx.bucket.clone()) PutBucketNotification::new(ctx.client.clone(), ctx.bucket.clone())
.notification_config(config) .notification_config(config)
}, },
) )
@ -42,7 +42,7 @@ pub(crate) fn bench_get_bucket_notification(criterion: &mut Criterion) {
let ctx = Ctx2::new().await; let ctx = Ctx2::new().await;
let config = create_bucket_notification_config_example(); let config = create_bucket_notification_config_example();
ctx.client ctx.client
.set_bucket_notification(&ctx.bucket) .put_bucket_notification(&ctx.bucket)
.notification_config(config) .notification_config(config)
.send() .send()
.await .await

View File

@ -16,18 +16,18 @@
use crate::common_benches::{Ctx2, benchmark_s3_api}; use crate::common_benches::{Ctx2, benchmark_s3_api};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{DeleteBucketPolicy, GetBucketPolicy, SetBucketPolicy}; use minio::s3::builders::{DeleteBucketPolicy, GetBucketPolicy, PutBucketPolicy};
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use minio_common::example::create_bucket_policy_config_example; use minio_common::example::create_bucket_policy_config_example;
pub(crate) fn bench_set_bucket_policy(criterion: &mut Criterion) { pub(crate) fn bench_put_bucket_policy(criterion: &mut Criterion) {
benchmark_s3_api( benchmark_s3_api(
"set_bucket_policy", "put_bucket_policy",
criterion, criterion,
|| async { Ctx2::new().await }, || async { Ctx2::new().await },
|ctx| { |ctx| {
let config = create_bucket_policy_config_example(&ctx.bucket); let config = create_bucket_policy_config_example(&ctx.bucket);
SetBucketPolicy::new(ctx.client.clone(), ctx.bucket.clone()).config(config) PutBucketPolicy::new(ctx.client.clone(), ctx.bucket.clone()).config(config)
}, },
) )
} }
@ -38,7 +38,7 @@ pub(crate) fn bench_get_bucket_policy(criterion: &mut Criterion) {
|| async { || async {
let ctx = Ctx2::new().await; let ctx = Ctx2::new().await;
let config = create_bucket_policy_config_example(&ctx.bucket); let config = create_bucket_policy_config_example(&ctx.bucket);
SetBucketPolicy::new(ctx.client.clone(), ctx.bucket.clone()) PutBucketPolicy::new(ctx.client.clone(), ctx.bucket.clone())
.config(config) .config(config)
.send() .send()
.await .await

View File

@ -17,32 +17,32 @@ use crate::common_benches::{Ctx2, benchmark_s3_api};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{ use minio::s3::builders::{
DeleteBucketReplication, GetBucketReplication, SetBucketReplication, VersioningStatus, DeleteBucketReplication, GetBucketReplication, PutBucketReplication, VersioningStatus,
}; };
use minio::s3::response::SetBucketVersioningResponse; use minio::s3::response::PutBucketVersioningResponse;
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use minio_common::example::create_bucket_replication_config_example; use minio_common::example::create_bucket_replication_config_example;
#[allow(dead_code)] #[allow(dead_code)]
pub(crate) fn bench_set_bucket_replication(criterion: &mut Criterion) { pub(crate) fn bench_put_bucket_replication(criterion: &mut Criterion) {
benchmark_s3_api( benchmark_s3_api(
"set_bucket_replication", "put_bucket_replication",
criterion, criterion,
|| async { || async {
let mut ctx = Ctx2::new().await; let mut ctx = Ctx2::new().await;
ctx.new_aux().await; ctx.new_aux().await;
let _resp: SetBucketVersioningResponse = ctx let _resp: PutBucketVersioningResponse = ctx
.client .client
.set_bucket_versioning(&ctx.bucket) .put_bucket_versioning(&ctx.bucket)
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await .await
.unwrap(); .unwrap();
let _resp: SetBucketVersioningResponse = ctx let _resp: PutBucketVersioningResponse = ctx
.client .client
.set_bucket_versioning(&ctx.aux_bucket.clone().unwrap()) .put_bucket_versioning(&ctx.aux_bucket.clone().unwrap())
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await .await
@ -53,7 +53,7 @@ pub(crate) fn bench_set_bucket_replication(criterion: &mut Criterion) {
|ctx| { |ctx| {
let config = let config =
create_bucket_replication_config_example(ctx.aux_bucket.clone().unwrap().as_str()); create_bucket_replication_config_example(ctx.aux_bucket.clone().unwrap().as_str());
SetBucketReplication::new(ctx.client.clone(), ctx.bucket.clone()) PutBucketReplication::new(ctx.client.clone(), ctx.bucket.clone())
.replication_config(config) .replication_config(config)
}, },
) )
@ -67,17 +67,17 @@ pub(crate) fn bench_get_bucket_replication(criterion: &mut Criterion) {
let mut ctx = Ctx2::new().await; let mut ctx = Ctx2::new().await;
ctx.new_aux().await; ctx.new_aux().await;
let _resp: SetBucketVersioningResponse = ctx let _resp: PutBucketVersioningResponse = ctx
.client .client
.set_bucket_versioning(&ctx.bucket) .put_bucket_versioning(&ctx.bucket)
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await .await
.unwrap(); .unwrap();
let _resp: SetBucketVersioningResponse = ctx let _resp: PutBucketVersioningResponse = ctx
.client .client
.set_bucket_versioning(&ctx.aux_bucket.clone().unwrap()) .put_bucket_versioning(&ctx.aux_bucket.clone().unwrap())
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await .await
@ -97,17 +97,17 @@ pub(crate) fn bench_delete_bucket_replication(criterion: &mut Criterion) {
let mut ctx = Ctx2::new().await; let mut ctx = Ctx2::new().await;
ctx.new_aux().await; ctx.new_aux().await;
let _resp: SetBucketVersioningResponse = ctx let _resp: PutBucketVersioningResponse = ctx
.client .client
.set_bucket_versioning(&ctx.bucket) .put_bucket_versioning(&ctx.bucket)
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await .await
.unwrap(); .unwrap();
let _resp: SetBucketVersioningResponse = ctx let _resp: PutBucketVersioningResponse = ctx
.client .client
.set_bucket_versioning(&ctx.aux_bucket.clone().unwrap()) .put_bucket_versioning(&ctx.aux_bucket.clone().unwrap())
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await .await

View File

@ -16,51 +16,52 @@
use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode}; use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{DeleteBucketTags, GetBucketTags, SetBucketTags}; use minio::s3::builders::{DeleteBucketTagging, GetBucketTagging, PutBucketTagging};
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use minio_common::example::create_tags_example; use minio_common::example::create_tags_example;
pub(crate) fn bench_set_bucket_tags(criterion: &mut Criterion) { pub(crate) fn bench_put_bucket_tagging(criterion: &mut Criterion) {
if skip_express_mode("bench_set_bucket_tags") { if skip_express_mode("bench_put_bucket_tagging") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"set_bucket_tags", "put_bucket_tagging",
criterion, criterion,
|| async { Ctx2::new().await }, || async { Ctx2::new().await },
|ctx| { |ctx| {
SetBucketTags::new(ctx.client.clone(), ctx.bucket.clone()).tags(create_tags_example()) PutBucketTagging::new(ctx.client.clone(), ctx.bucket.clone())
.tags(create_tags_example())
}, },
) )
} }
pub(crate) fn bench_get_bucket_tags(criterion: &mut Criterion) { pub(crate) fn bench_get_bucket_tagging(criterion: &mut Criterion) {
if skip_express_mode("bench_get_bucket_tags") { if skip_express_mode("bench_get_bucket_tagging") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"get_bucket_tags", "get_bucket_tagging",
criterion, criterion,
|| async { || async {
let ctx = Ctx2::new().await; let ctx = Ctx2::new().await;
ctx.client ctx.client
.set_bucket_tags(&ctx.bucket) .put_bucket_tagging(&ctx.bucket)
.tags(create_tags_example()) .tags(create_tags_example())
.send() .send()
.await .await
.unwrap(); .unwrap();
ctx ctx
}, },
|ctx| GetBucketTags::new(ctx.client.clone(), ctx.bucket.clone()), |ctx| GetBucketTagging::new(ctx.client.clone(), ctx.bucket.clone()),
) )
} }
pub(crate) fn bench_delete_bucket_tags(criterion: &mut Criterion) { pub(crate) fn bench_delete_bucket_tagging(criterion: &mut Criterion) {
if skip_express_mode("bench_delete_bucket_tags") { if skip_express_mode("bench_delete_bucket_tagging") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"delete_bucket_tags", "delete_bucket_tagging",
criterion, criterion,
|| async { Ctx2::new().await }, || async { Ctx2::new().await },
|ctx| DeleteBucketTags::new(ctx.client.clone(), ctx.bucket.clone()), |ctx| DeleteBucketTagging::new(ctx.client.clone(), ctx.bucket.clone()),
) )
} }

View File

@ -16,7 +16,7 @@
use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode}; use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{GetBucketVersioning, SetBucketVersioning, VersioningStatus}; use minio::s3::builders::{GetBucketVersioning, PutBucketVersioning, VersioningStatus};
pub(crate) fn bench_get_bucket_versioning(criterion: &mut Criterion) { pub(crate) fn bench_get_bucket_versioning(criterion: &mut Criterion) {
if skip_express_mode("bench_get_bucket_versioning") { if skip_express_mode("bench_get_bucket_versioning") {
@ -29,16 +29,16 @@ pub(crate) fn bench_get_bucket_versioning(criterion: &mut Criterion) {
|ctx| GetBucketVersioning::new(ctx.client.clone(), ctx.bucket.clone()), |ctx| GetBucketVersioning::new(ctx.client.clone(), ctx.bucket.clone()),
) )
} }
pub(crate) fn bench_set_bucket_versioning(criterion: &mut Criterion) { pub(crate) fn bench_put_bucket_versioning(criterion: &mut Criterion) {
if skip_express_mode("bench_set_bucket_versioning") { if skip_express_mode("bench_put_bucket_versioning") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"set_bucket_versioning", "put_bucket_versioning",
criterion, criterion,
|| async { Ctx2::new().await }, || async { Ctx2::new().await },
|ctx| { |ctx| {
SetBucketVersioning::new(ctx.client.clone(), ctx.bucket.clone()) PutBucketVersioning::new(ctx.client.clone(), ctx.bucket.clone())
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
}, },
) )

View File

@ -16,59 +16,39 @@
use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode}; use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{ use minio::s3::builders::{GetObjectLegalHold, PutObjectLegalHold};
DisableObjectLegalHold, EnableObjectLegalHold, IsObjectLegalHoldEnabled,
};
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
pub(crate) fn bench_enable_object_legal_hold(criterion: &mut Criterion) { pub(crate) fn bench_put_object_legal_hold(criterion: &mut Criterion) {
if skip_express_mode("bench_enable_object_legal_hold") { if skip_express_mode("bench_put_object_legal_hold") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"enable_object_legal_hold", "put_object_legal_hold",
criterion, criterion,
|| async { Ctx2::new_with_object(true).await }, || async { Ctx2::new_with_object(true).await },
|ctx| { |ctx| {
EnableObjectLegalHold::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()) PutObjectLegalHold::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone())
.legal_hold(Some(true))
}, },
) )
} }
pub(crate) fn bench_disable_object_legal_hold(criterion: &mut Criterion) { pub(crate) fn bench_get_object_legal_hold(criterion: &mut Criterion) {
if skip_express_mode("bench_disable_object_legal_hold") { if skip_express_mode("bench_get_object_legal_hold") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"disable_object_legal_hold", "get_object_legal_hold",
criterion,
|| async { Ctx2::new_with_object(true).await },
|ctx| {
DisableObjectLegalHold::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone())
},
)
}
pub(crate) fn bench_is_object_legal_hold(criterion: &mut Criterion) {
if skip_express_mode("bench_is_object_legal_hold") {
return;
}
benchmark_s3_api(
"is_object_legal_hold",
criterion, criterion,
|| async { || async {
let ctx = Ctx2::new_with_object(true).await; let ctx = Ctx2::new_with_object(true).await;
ctx.client ctx.client
.enable_object_legal_hold(&ctx.bucket, &ctx.object) .get_object_legal_hold(&ctx.bucket, &ctx.object)
.send() .send()
.await .await
.unwrap(); .unwrap();
ctx ctx
}, },
|ctx| { |ctx| GetObjectLegalHold::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()),
IsObjectLegalHoldEnabled::new(
ctx.client.clone(),
ctx.bucket.clone(),
ctx.object.clone(),
)
},
) )
} }

View File

@ -15,20 +15,20 @@
use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode}; use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{DeleteObjectLockConfig, GetObjectLockConfig, SetObjectLockConfig}; use minio::s3::builders::{DeleteObjectLockConfig, GetObjectLockConfig, PutObjectLockConfig};
use minio_common::example::create_object_lock_config_example; use minio_common::example::create_object_lock_config_example;
pub(crate) fn bench_set_object_lock_config(criterion: &mut Criterion) { pub(crate) fn bench_put_object_lock_config(criterion: &mut Criterion) {
if skip_express_mode("bench_set_object_lock_config") { if skip_express_mode("bench_put_object_lock_config") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"set_object_lock_config", "put_object_lock_config",
criterion, criterion,
|| async { Ctx2::new_with_object(true).await }, || async { Ctx2::new_with_object(true).await },
|ctx| { |ctx| {
let config = create_object_lock_config_example(); let config = create_object_lock_config_example();
SetObjectLockConfig::new(ctx.client.clone(), ctx.bucket.clone()).config(config) PutObjectLockConfig::new(ctx.client.clone(), ctx.bucket.clone()).config(config)
}, },
) )
} }

View File

@ -16,21 +16,21 @@
use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode}; use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{GetObjectRetention, SetObjectRetention}; use minio::s3::builders::{GetObjectRetention, PutObjectRetention};
use minio::s3::response::SetObjectRetentionResponse; use minio::s3::response::PutObjectRetentionResponse;
use minio::s3::types::{RetentionMode, S3Api}; use minio::s3::types::{RetentionMode, S3Api};
use minio::s3::utils::utc_now; use minio::s3::utils::utc_now;
pub(crate) fn bench_set_object_retention(criterion: &mut Criterion) { pub(crate) fn bench_put_object_retention(criterion: &mut Criterion) {
if skip_express_mode("bench_set_object_retention") { if skip_express_mode("bench_put_object_retention") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"set_object_retention", "put_object_retention",
criterion, criterion,
|| async { Ctx2::new_with_object(true).await }, || async { Ctx2::new_with_object(true).await },
|ctx| { |ctx| {
SetObjectRetention::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()) PutObjectRetention::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone())
.retention_mode(Some(RetentionMode::GOVERNANCE)) .retention_mode(Some(RetentionMode::GOVERNANCE))
.retain_until_date(Some(utc_now() + chrono::Duration::days(1))) .retain_until_date(Some(utc_now() + chrono::Duration::days(1)))
}, },
@ -45,8 +45,8 @@ pub(crate) fn bench_get_object_retention(criterion: &mut Criterion) {
criterion, criterion,
|| async { || async {
let ctx = Ctx2::new_with_object(true).await; let ctx = Ctx2::new_with_object(true).await;
let _resp: SetObjectRetentionResponse = let _resp: PutObjectRetentionResponse =
SetObjectRetention::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()) PutObjectRetention::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone())
.retention_mode(Some(RetentionMode::GOVERNANCE)) .retention_mode(Some(RetentionMode::GOVERNANCE))
.retain_until_date(Some(utc_now() + chrono::Duration::days(1))) .retain_until_date(Some(utc_now() + chrono::Duration::days(1)))
.send() .send()

View File

@ -16,44 +16,44 @@
use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode}; use crate::common_benches::{Ctx2, benchmark_s3_api, skip_express_mode};
use criterion::Criterion; use criterion::Criterion;
use minio::s3::builders::{GetObjectTags, SetObjectTags}; use minio::s3::builders::{GetObjectTagging, PutObjectTagging};
use minio::s3::response::SetObjectTagsResponse; use minio::s3::response::PutObjectTaggingResponse;
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use minio_common::example::create_tags_example; use minio_common::example::create_tags_example;
pub(crate) fn bench_set_object_tags(criterion: &mut Criterion) { pub(crate) fn bench_put_object_tagging(criterion: &mut Criterion) {
if skip_express_mode("bench_set_object_tags") { if skip_express_mode("bench_put_object_tagging") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"set_object_tags", "put_object_tagging",
criterion, criterion,
|| async { Ctx2::new_with_object(false).await }, || async { Ctx2::new_with_object(false).await },
|ctx| { |ctx| {
SetObjectTags::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()) PutObjectTagging::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone())
.tags(create_tags_example()) .tags(create_tags_example())
}, },
) )
} }
pub(crate) fn bench_get_object_tags(criterion: &mut Criterion) { pub(crate) fn bench_get_object_tagging(criterion: &mut Criterion) {
if skip_express_mode("bench_get_object_tags") { if skip_express_mode("bench_get_object_tagging") {
return; return;
} }
benchmark_s3_api( benchmark_s3_api(
"get_object_tags", "get_object_tagging",
criterion, criterion,
|| async { || async {
let ctx = Ctx2::new_with_object(false).await; let ctx = Ctx2::new_with_object(false).await;
let _resp: SetObjectTagsResponse = ctx let _resp: PutObjectTaggingResponse = ctx
.client .client
.set_object_tags(&ctx.bucket, &ctx.object) .put_object_tagging(&ctx.bucket, &ctx.object)
.tags(create_tags_example()) .tags(create_tags_example())
.send() .send()
.await .await
.unwrap(); .unwrap();
ctx ctx
}, },
|ctx| GetObjectTags::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()), |ctx| GetObjectTagging::new(ctx.client.clone(), ctx.bucket.clone(), ctx.object.clone()),
) )
} }

View File

@ -16,7 +16,7 @@
use criterion::Criterion; use criterion::Criterion;
use minio::s3::Client; use minio::s3::Client;
use minio::s3::error::Error; use minio::s3::error::Error;
use minio::s3::response::{MakeBucketResponse, PutObjectContentResponse}; use minio::s3::response::{CreateBucketResponse, PutObjectContentResponse};
use minio::s3::types::{FromS3Response, S3Api, S3Request}; use minio::s3::types::{FromS3Response, S3Api, S3Request};
use minio_common::cleanup_guard::CleanupGuard; use minio_common::cleanup_guard::CleanupGuard;
use minio_common::test_context::TestContext; use minio_common::test_context::TestContext;
@ -61,9 +61,9 @@ impl Ctx2 {
} }
let ctx = TestContext::new_from_env(); let ctx = TestContext::new_from_env();
let bucket_name: String = rand_bucket_name(); let bucket_name: String = rand_bucket_name();
let _resp: MakeBucketResponse = ctx let _resp: CreateBucketResponse = ctx
.client .client
.make_bucket(&bucket_name) .create_bucket(&bucket_name)
.object_lock(object_lock) .object_lock(object_lock)
.send() .send()
.await .await
@ -92,9 +92,9 @@ impl Ctx2 {
let bucket_name: String = rand_bucket_name(); let bucket_name: String = rand_bucket_name();
self.aux_bucket = Some(bucket_name.clone()); self.aux_bucket = Some(bucket_name.clone());
self._aux_cleanup = Some(CleanupGuard::new(self.client.clone(), &bucket_name)); self._aux_cleanup = Some(CleanupGuard::new(self.client.clone(), &bucket_name));
let _resp: MakeBucketResponse = self let _resp: CreateBucketResponse = self
.client .client
.make_bucket(&bucket_name) .create_bucket(&bucket_name)
.object_lock(false) .object_lock(false)
.send() .send()
.await .await

View File

@ -50,7 +50,7 @@ impl Drop for CleanupGuard {
// do the actual removal of the bucket // do the actual removal of the bucket
match timeout( match timeout(
std::time::Duration::from_secs(60), std::time::Duration::from_secs(60),
client.remove_and_purge_bucket(&bucket_name), client.delete_and_purge_bucket(&bucket_name),
) )
.await .await
{ {

View File

@ -151,7 +151,12 @@ impl TestContext {
/// ``` /// ```
pub async fn create_bucket_helper(&self) -> (String, CleanupGuard) { pub async fn create_bucket_helper(&self) -> (String, CleanupGuard) {
let bucket_name = rand_bucket_name(); let bucket_name = rand_bucket_name();
let _resp = self.client.make_bucket(&bucket_name).send().await.unwrap(); let _resp = self
.client
.create_bucket(&bucket_name)
.send()
.await
.unwrap();
let guard = CleanupGuard::new(self.client.clone(), &bucket_name); let guard = CleanupGuard::new(self.client.clone(), &bucket_name);
(bucket_name, guard) (bucket_name, guard)
} }

View File

@ -17,7 +17,7 @@ mod common;
use crate::common::{create_bucket_if_not_exists, create_client_on_play}; use crate::common::{create_bucket_if_not_exists, create_client_on_play};
use minio::s3::Client; use minio::s3::Client;
use minio::s3::response::{GetBucketEncryptionResponse, SetBucketEncryptionResponse}; use minio::s3::response::{GetBucketEncryptionResponse, PutBucketEncryptionResponse};
use minio::s3::types::{S3Api, SseConfig}; use minio::s3::types::{S3Api, SseConfig};
#[tokio::main] #[tokio::main]
@ -35,8 +35,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let config = SseConfig::default(); let config = SseConfig::default();
log::info!("going to set encryption config={:?}", config); log::info!("going to set encryption config={:?}", config);
let _resp: SetBucketEncryptionResponse = client let _resp: PutBucketEncryptionResponse = client
.set_bucket_encryption(bucket_name) .put_bucket_encryption(bucket_name)
.sse_config(config.clone()) .sse_config(config.clone())
.send() .send()
.await?; .await?;

View File

@ -18,7 +18,7 @@ mod common;
use crate::common::{create_bucket_if_not_exists, create_client_on_play}; use crate::common::{create_bucket_if_not_exists, create_client_on_play};
use minio::s3::Client; use minio::s3::Client;
use minio::s3::response::{ use minio::s3::response::{
DeleteBucketLifecycleResponse, GetBucketLifecycleResponse, SetBucketLifecycleResponse, DeleteBucketLifecycleResponse, GetBucketLifecycleResponse, PutBucketLifecycleResponse,
}; };
use minio::s3::types::{Filter, LifecycleConfig, LifecycleRule, S3Api}; use minio::s3::types::{Filter, LifecycleConfig, LifecycleRule, S3Api};
@ -57,8 +57,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
transition_storage_class: None, transition_storage_class: None,
}]; }];
let resp: SetBucketLifecycleResponse = client let resp: PutBucketLifecycleResponse = client
.set_bucket_lifecycle(bucket_name) .put_bucket_lifecycle(bucket_name)
.life_cycle_config(LifecycleConfig { rules }) .life_cycle_config(LifecycleConfig { rules })
.send() .send()
.await?; .await?;

View File

@ -18,7 +18,7 @@ mod common;
use crate::common::{create_bucket_if_not_exists, create_client_on_play}; use crate::common::{create_bucket_if_not_exists, create_client_on_play};
use minio::s3::Client; use minio::s3::Client;
use minio::s3::builders::VersioningStatus; use minio::s3::builders::VersioningStatus;
use minio::s3::response::{GetBucketVersioningResponse, SetBucketVersioningResponse}; use minio::s3::response::{GetBucketVersioningResponse, PutBucketVersioningResponse};
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
#[tokio::main] #[tokio::main]
@ -37,8 +37,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
resp.mfa_delete resp.mfa_delete
); );
let _resp: SetBucketVersioningResponse = client let _resp: PutBucketVersioningResponse = client
.set_bucket_versioning(bucket_name) .put_bucket_versioning(bucket_name)
.versioning_status(VersioningStatus::Enabled) .versioning_status(VersioningStatus::Enabled)
.send() .send()
.await?; .await?;
@ -52,8 +52,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
resp.mfa_delete resp.mfa_delete
); );
let _resp: SetBucketVersioningResponse = client let _resp: PutBucketVersioningResponse = client
.set_bucket_versioning(bucket_name) .put_bucket_versioning(bucket_name)
.versioning_status(VersioningStatus::Suspended) .versioning_status(VersioningStatus::Suspended)
.send() .send()
.await?; .await?;
@ -67,8 +67,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
resp.mfa_delete resp.mfa_delete
); );
let _resp: SetBucketVersioningResponse = client let _resp: PutBucketVersioningResponse = client
.set_bucket_versioning(bucket_name) .put_bucket_versioning(bucket_name)
//.versioning_status(VersioningStatus::Suspended) //.versioning_status(VersioningStatus::Suspended)
.send() .send()
.await?; .await?;

View File

@ -43,7 +43,7 @@ pub async fn create_bucket_if_not_exists(
// Make 'bucket_name' bucket if not exist. // Make 'bucket_name' bucket if not exist.
if !resp.exists { if !resp.exists {
client.make_bucket(bucket_name).send().await.unwrap(); client.create_bucket(bucket_name).send().await.unwrap();
}; };
Ok(()) Ok(())
} }

View File

@ -20,7 +20,7 @@ use minio::s3::builders::ObjectContent;
use minio::s3::client::ClientBuilder; use minio::s3::client::ClientBuilder;
use minio::s3::creds::StaticProvider; use minio::s3::creds::StaticProvider;
use minio::s3::http::BaseUrl; use minio::s3::http::BaseUrl;
use minio::s3::response::ObjectPromptResponse; use minio::s3::response::GetObjectPromptResponse;
use minio::s3::types::S3Api; use minio::s3::types::S3Api;
use std::path::Path; use std::path::Path;
@ -66,8 +66,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
filename.display() filename.display()
); );
let resp: ObjectPromptResponse = client let resp: GetObjectPromptResponse = client
.object_prompt(bucket_name, object_name, "what is it about?") .get_object_prompt(bucket_name, object_name, "what is it about?")
//.lambda_arn("arn:minio:s3-object-lambda::_:webhook") // this is the default value //.lambda_arn("arn:minio:s3-object-lambda::_:webhook") // this is the default value
.send() .send()
.await?; .await?;

View File

@ -48,7 +48,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
let resp: BucketExistsResponse = client.bucket_exists(&args.bucket).send().await.unwrap(); let resp: BucketExistsResponse = client.bucket_exists(&args.bucket).send().await.unwrap();
if !resp.exists { if !resp.exists {
client.make_bucket(&args.bucket).send().await.unwrap(); client.create_bucket(&args.bucket).send().await.unwrap();
} }
let content = ObjectContent::from(args.file.as_path()); let content = ObjectContent::from(args.file.as_path());

4
rust-toolchain.toml Normal file
View File

@ -0,0 +1,4 @@
[toolchain]
channel = "1.86.0"
components = ["clippy", "rustfmt"]
#targets = ["x86_64-unknown-linux-musl"]

View File

@ -13,7 +13,48 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
#![allow(clippy::tabs_in_doc_comments)] //! # MinIO Rust SDK (`minio-rs`)
//!
//! This crate provides a strongly-typed, async-first interface to the MinIO and Amazon S3-compatible object storage APIs.
//!
//! Each supported S3 operation has a corresponding request builder (e.g., [`BucketExists`], [`PutObject`], [`UploadPartCopy`]),
//! which allows users to configure request parameters using a fluent builder pattern.
//!
//! All request builders implement the [`S3Api`] trait, which provides the async [`send`](crate::s3::types::S3Api::send) method
//! to execute the request and return a typed response.
//!
//! ## Basic Usage
//!
//! ```no_run
//! use minio::s3::Client;
//! use minio::s3::types::S3Api;
//! use minio::s3::response::BucketExistsResponse;
//!
//! #[tokio::main]
//! async fn main() {
//! let client: Client = Default::default(); // configure your client
//!
//! let exists: BucketExistsResponse = client
//! .bucket_exists("my-bucket")
//! .send()
//! .await
//! .expect("request failed");
//!
//! println!("Bucket exists: {}", exists.exists);
//! }
//! ```
//!
//! ## Features
//! - Request builder pattern for ergonomic API usage
//! - Full async/await support via [`tokio`]
//! - Strongly-typed responses
//! - Transparent error handling via `Result<T, Error>`
//!
//! ## Design
//! - Each API method on the [`Client`] returns a builder struct
//! - Builders implement [`ToS3Request`] for request conversion and [`S3Api`] for execution
//! - Responses implement [`FromS3Response`] for consistent deserialization
#![allow(clippy::result_large_err)] #![allow(clippy::result_large_err)]
#![allow(clippy::too_many_arguments)] #![allow(clippy::too_many_arguments)]
pub mod s3; pub mod s3;

View File

@ -19,50 +19,49 @@ mod append_object;
mod bucket_common; mod bucket_common;
mod bucket_exists; mod bucket_exists;
mod copy_object; mod copy_object;
mod create_bucket;
mod delete_bucket;
mod delete_bucket_encryption; mod delete_bucket_encryption;
mod delete_bucket_lifecycle; mod delete_bucket_lifecycle;
mod delete_bucket_notification; mod delete_bucket_notification;
mod delete_bucket_policy; mod delete_bucket_policy;
mod delete_bucket_replication; mod delete_bucket_replication;
mod delete_bucket_tags; mod delete_bucket_tagging;
mod delete_object_lock_config; mod delete_object_lock_config;
mod delete_object_tags; mod delete_object_tagging;
mod disable_object_legal_hold; mod delete_objects;
mod enable_object_legal_hold;
mod get_bucket_encryption; mod get_bucket_encryption;
mod get_bucket_lifecycle; mod get_bucket_lifecycle;
mod get_bucket_notification; mod get_bucket_notification;
mod get_bucket_policy; mod get_bucket_policy;
mod get_bucket_replication; mod get_bucket_replication;
mod get_bucket_tags; mod get_bucket_tagging;
mod get_bucket_versioning; mod get_bucket_versioning;
mod get_object; mod get_object;
mod get_object_legal_hold;
mod get_object_lock_config; mod get_object_lock_config;
mod get_object_prompt;
mod get_object_retention; mod get_object_retention;
mod get_object_tags; mod get_object_tagging;
mod get_presigned_object_url; mod get_presigned_object_url;
mod get_presigned_policy_form_data; mod get_presigned_policy_form_data;
mod get_region; mod get_region;
mod is_object_legal_hold_enabled; mod list_bucket_notification;
mod list_buckets; mod list_buckets;
mod list_objects; mod list_objects;
mod listen_bucket_notification; mod put_bucket_encryption;
mod make_bucket; mod put_bucket_lifecycle;
mod object_prompt; mod put_bucket_notification;
mod put_bucket_policy;
mod put_bucket_replication;
mod put_bucket_tagging;
mod put_bucket_versioning;
mod put_object; mod put_object;
mod remove_bucket; mod put_object_legal_hold;
mod remove_objects; mod put_object_lock_config;
mod put_object_retention;
mod put_object_tagging;
mod select_object_content; mod select_object_content;
mod set_bucket_encryption;
mod set_bucket_lifecycle;
mod set_bucket_notification;
mod set_bucket_policy;
mod set_bucket_replication;
mod set_bucket_tags;
mod set_bucket_versioning;
mod set_object_lock_config;
mod set_object_retention;
mod set_object_tags;
mod stat_object; mod stat_object;
pub use crate::s3::object_content::*; pub use crate::s3::object_content::*;
@ -70,48 +69,47 @@ pub use append_object::*;
pub use bucket_common::*; pub use bucket_common::*;
pub use bucket_exists::*; pub use bucket_exists::*;
pub use copy_object::*; pub use copy_object::*;
pub use create_bucket::*;
pub use delete_bucket::*;
pub use delete_bucket_encryption::*; pub use delete_bucket_encryption::*;
pub use delete_bucket_lifecycle::*; pub use delete_bucket_lifecycle::*;
pub use delete_bucket_notification::*; pub use delete_bucket_notification::*;
pub use delete_bucket_policy::*; pub use delete_bucket_policy::*;
pub use delete_bucket_replication::*; pub use delete_bucket_replication::*;
pub use delete_bucket_tags::*; pub use delete_bucket_tagging::*;
pub use delete_object_lock_config::*; pub use delete_object_lock_config::*;
pub use delete_object_tags::*; pub use delete_object_tagging::*;
pub use disable_object_legal_hold::*; pub use delete_objects::*;
pub use enable_object_legal_hold::*;
pub use get_bucket_encryption::*; pub use get_bucket_encryption::*;
pub use get_bucket_lifecycle::*; pub use get_bucket_lifecycle::*;
pub use get_bucket_notification::*; pub use get_bucket_notification::*;
pub use get_bucket_policy::*; pub use get_bucket_policy::*;
pub use get_bucket_replication::*; pub use get_bucket_replication::*;
pub use get_bucket_tags::*; pub use get_bucket_tagging::*;
pub use get_bucket_versioning::*; pub use get_bucket_versioning::*;
pub use get_object::*; pub use get_object::*;
pub use get_object_legal_hold::*;
pub use get_object_lock_config::*; pub use get_object_lock_config::*;
pub use get_object_prompt::*;
pub use get_object_retention::*; pub use get_object_retention::*;
pub use get_object_tags::*; pub use get_object_tagging::*;
pub use get_presigned_object_url::*; pub use get_presigned_object_url::*;
pub use get_presigned_policy_form_data::*; pub use get_presigned_policy_form_data::*;
pub use get_region::*; pub use get_region::*;
pub use is_object_legal_hold_enabled::*; pub use list_bucket_notification::*;
pub use list_buckets::*; pub use list_buckets::*;
pub use list_objects::*; pub use list_objects::*;
pub use listen_bucket_notification::*; pub use put_bucket_encryption::*;
pub use make_bucket::*; pub use put_bucket_lifecycle::*;
pub use object_prompt::*; pub use put_bucket_notification::*;
pub use put_bucket_policy::*;
pub use put_bucket_replication::*;
pub use put_bucket_tagging::*;
pub use put_bucket_versioning::*;
pub use put_object::*; pub use put_object::*;
pub use remove_bucket::*; pub use put_object_legal_hold::*;
pub use remove_objects::*; pub use put_object_lock_config::*;
pub use put_object_retention::*;
pub use put_object_tagging::*;
pub use select_object_content::*; pub use select_object_content::*;
pub use set_bucket_encryption::*;
pub use set_bucket_lifecycle::*;
pub use set_bucket_notification::*;
pub use set_bucket_policy::*;
pub use set_bucket_replication::*;
pub use set_bucket_tags::*;
pub use set_bucket_versioning::*;
pub use set_object_lock_config::*;
pub use set_object_retention::*;
pub use set_object_tags::*;
pub use stat_object::*; pub use stat_object::*;

View File

@ -28,7 +28,11 @@ use http::Method;
use std::sync::Arc; use std::sync::Arc;
// region: append-object // region: append-object
#[derive(Debug, Clone, Default)]
/// Argument builder for the [`AppendObject`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-objects-append.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::append_object`](crate::s3::client::Client::append_object) method.
#[derive(Clone, Debug, Default)]
pub struct AppendObject { pub struct AppendObject {
client: Client, client: Client,
@ -107,9 +111,14 @@ impl ToS3Request for AppendObject {
// region: append-object-content // region: append-object-content
/// AppendObjectContent takes a `ObjectContent` stream and appends it to MinIO/S3. /// Argument builder for the [`AppendObject`](https://docs.aws.amazon.com/AmazonS3/latest/userguide/directory-buckets-objects-append.html) S3 API operation.
/// ///
/// It is a higher level API and handles multipart appends transparently. /// This struct constructs the parameters required for the [`Client::append_object_content`](crate::s3::client::Client::append_object_content) method.
/// It is High-level API for appending content to an object using multipart uploads.
///
/// `AppendObjectContent` consumes an [`ObjectContent`] stream and transparently appends it to an existing object in MinIO or S3,
/// managing multipart upload details internally.
#[derive(Default)]
pub struct AppendObjectContent { pub struct AppendObjectContent {
client: Client, client: Client,
@ -284,12 +293,7 @@ impl AppendObjectContent {
part_number += 1; part_number += 1;
let buffer_size = part_content.len() as u64; let buffer_size = part_content.len() as u64;
assert!( assert!(buffer_size <= part_size, "{buffer_size} <= {part_size}",);
buffer_size <= part_size,
"{:?} <= {:?}",
buffer_size,
part_size
);
if buffer_size == 0 && part_number > 1 { if buffer_size == 0 && part_number > 1 {
// We are done as we appended at least 1 part and we have // We are done as we appended at least 1 part and we have

View File

@ -18,7 +18,7 @@ use std::marker::PhantomData;
use crate::s3::client::Client; use crate::s3::client::Client;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
#[derive(Clone, Default)] #[derive(Clone, Debug, Default)]
pub struct BucketCommon<A> { pub struct BucketCommon<A> {
pub(crate) client: Client, pub(crate) client: Client,

View File

@ -20,10 +20,10 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::check_bucket_name; use crate::s3::utils::check_bucket_name;
use http::Method; use http::Method;
/// Argument builder for [bucket_exists()](Client::bucket_exists) API /// This struct constructs the parameters required for the [`Client::bucket_exists`](crate::s3::client::Client::bucket_exists) method.
pub type BucketExists = BucketCommon<BucketExistsPhantomData>; pub type BucketExists = BucketCommon<BucketExistsPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct BucketExistsPhantomData; pub struct BucketExistsPhantomData;
impl S3Api for BucketExists { impl S3Api for BucketExists {

View File

@ -31,7 +31,9 @@ use http::Method;
use std::collections::HashMap; use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
/// Argument builder for [UploadPartCopy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html) API /// Argument builder for the [`UploadPartCopy`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::upload_part_copy`](crate::s3::client::Client::upload_part_copy) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct UploadPartCopy { pub struct UploadPartCopy {
client: Client, client: Client,
@ -98,8 +100,7 @@ impl ToS3Request for UploadPartCopy {
} }
if !(1..=MAX_MULTIPART_COUNT).contains(&self.part_number) { if !(1..=MAX_MULTIPART_COUNT).contains(&self.part_number) {
return Err(Error::InvalidPartNumber(format!( return Err(Error::InvalidPartNumber(format!(
"part number must be between 1 and {}", "part number must be between 1 and {MAX_MULTIPART_COUNT}"
MAX_MULTIPART_COUNT
))); )));
} }
} }
@ -325,7 +326,7 @@ impl ToS3Request for CopyObjectInternal {
} }
} }
/// Argument builder for [copy_object()](Client::copy_object_old) API /// Argument builder for [copy_object()](Client::copy_object) API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct CopyObject { pub struct CopyObject {
client: Client, client: Client,
@ -409,9 +410,7 @@ impl CopyObject {
self.tagging_directive = tagging_directive; self.tagging_directive = tagging_directive;
self self
} }
}
impl CopyObject {
pub async fn send(self) -> Result<CopyObjectResponse, Error> { pub async fn send(self) -> Result<CopyObjectResponse, Error> {
{ {
if let Some(v) = &self.sse { if let Some(v) = &self.sse {
@ -612,9 +611,7 @@ impl ComposeObjectInternal {
self.sources = sources; self.sources = sources;
self self
} }
}
impl ComposeObjectInternal {
#[async_recursion] #[async_recursion]
pub async fn send(self) -> (Result<ComposeObjectResponse, Error>, String) { pub async fn send(self) -> (Result<ComposeObjectResponse, Error>, String) {
let mut upload_id = String::new(); let mut upload_id = String::new();
@ -754,7 +751,7 @@ impl ComposeObjectInternal {
let mut headers_copy = headers.clone(); let mut headers_copy = headers.clone();
headers_copy.add( headers_copy.add(
"x-amz-copy-source-range", "x-amz-copy-source-range",
format!("bytes={}-{}", offset, end_bytes), format!("bytes={offset}-{end_bytes}"),
); );
let resp: UploadPartCopyResponse = match self let resp: UploadPartCopyResponse = match self
@ -885,9 +882,7 @@ impl ComposeObject {
self.sources = sources; self.sources = sources;
self self
} }
}
impl ComposeObject {
pub async fn send(self) -> Result<ComposeObjectResponse, Error> { pub async fn send(self) -> Result<ComposeObjectResponse, Error> {
{ {
if let Some(v) = &self.sse { if let Some(v) = &self.sse {
@ -934,7 +929,7 @@ impl ComposeObject {
// region: misc // region: misc
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
/// Source object information for [compose object argument](ComposeObjectArgs) /// Source object information for [compose_object](Client::compose_object)
pub struct ComposeSource { pub struct ComposeSource {
pub extra_headers: Option<Multimap>, pub extra_headers: Option<Multimap>,
pub extra_query_params: Option<Multimap>, pub extra_query_params: Option<Multimap>,
@ -963,35 +958,23 @@ impl ComposeSource {
/// use minio::s3::builders::ComposeSource; /// use minio::s3::builders::ComposeSource;
/// let src = ComposeSource::new("my-src-bucket", "my-src-object").unwrap(); /// let src = ComposeSource::new("my-src-bucket", "my-src-object").unwrap();
/// ``` /// ```
pub fn new(bucket_name: &str, object_name: &str) -> Result<ComposeSource, Error> { pub fn new(bucket_name: &str, object_name: &str) -> Result<Self, Error> {
check_bucket_name(bucket_name, true)?; check_bucket_name(bucket_name, true)?;
check_object_name(object_name)?; check_object_name(object_name)?;
Ok(ComposeSource { Ok(Self {
extra_headers: None,
extra_query_params: None,
region: None,
bucket: bucket_name.to_owned(), bucket: bucket_name.to_owned(),
object: object_name.to_owned(), object: object_name.to_owned(),
version_id: None, ..Default::default()
ssec: None,
offset: None,
length: None,
match_etag: None,
not_match_etag: None,
modified_since: None,
unmodified_since: None,
object_size: None,
headers: None,
}) })
} }
pub fn get_object_size(&self) -> u64 { pub fn get_object_size(&self) -> u64 {
self.object_size.expect("A: ABORT: ComposeSource::build_headers() must be called prior to this method invocation. This shoud not happen.") self.object_size.expect("A: ABORT: ComposeSource::build_headers() must be called prior to this method invocation. This should not happen.")
} }
pub fn get_headers(&self) -> Multimap { pub fn get_headers(&self) -> Multimap {
self.headers.as_ref().expect("B: ABORT: ComposeSource::build_headers() must be called prior to this method invocation. This shoud not happen.").clone() self.headers.as_ref().expect("B: ABORT: ComposeSource::build_headers() must be called prior to this method invocation. This should not happen.").clone()
} }
pub fn build_headers(&mut self, object_size: u64, etag: String) -> Result<(), Error> { pub fn build_headers(&mut self, object_size: u64, etag: String) -> Result<(), Error> {
@ -1098,24 +1081,14 @@ pub struct CopySource {
} }
impl CopySource { impl CopySource {
pub fn new(bucket_name: &str, object_name: &str) -> Result<CopySource, Error> { pub fn new(bucket_name: &str, object_name: &str) -> Result<Self, Error> {
check_bucket_name(bucket_name, true)?; check_bucket_name(bucket_name, true)?;
check_object_name(object_name)?; check_object_name(object_name)?;
Ok(CopySource { Ok(Self {
extra_headers: None,
extra_query_params: None,
region: None,
bucket: bucket_name.to_owned(), bucket: bucket_name.to_owned(),
object: object_name.to_owned(), object: object_name.to_owned(),
version_id: None, ..Default::default()
ssec: None,
offset: None,
length: None,
match_etag: None,
not_match_etag: None,
modified_since: None,
unmodified_since: None,
}) })
} }
@ -1178,20 +1151,20 @@ fn into_headers_copy_object(
} }
if !tagging.is_empty() { if !tagging.is_empty() {
map.insert("x-amz-tagging".into(), tagging); map.add("x-amz-tagging", tagging);
} }
} }
if let Some(v) = retention { if let Some(v) = retention {
map.insert("x-amz-object-lock-mode".into(), v.mode.to_string()); map.add("x-amz-object-lock-mode", v.mode.to_string());
map.insert( map.add(
"x-amz-object-lock-retain-until-date".into(), "x-amz-object-lock-retain-until-date",
to_iso8601utc(v.retain_until_date), to_iso8601utc(v.retain_until_date),
); );
} }
if legal_hold { if legal_hold {
map.insert("x-amz-object-lock-legal-hold".into(), "ON".into()); map.add("x-amz-object-lock-legal-hold", "ON");
} }
map map

View File

@ -17,15 +17,17 @@ use crate::s3::Client;
use crate::s3::client::DEFAULT_REGION; use crate::s3::client::DEFAULT_REGION;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::MakeBucketResponse; use crate::s3::response::CreateBucketResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::check_bucket_name; use crate::s3::utils::check_bucket_name;
use http::Method; use http::Method;
/// Argument builder for [make_bucket()](Client::make_bucket) API /// Argument builder for the [`CreateBucket`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::create_bucket`](crate::s3::client::Client::create_bucket) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct MakeBucket { pub struct CreateBucket {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -36,7 +38,7 @@ pub struct MakeBucket {
object_lock: bool, object_lock: bool,
} }
impl MakeBucket { impl CreateBucket {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -66,11 +68,11 @@ impl MakeBucket {
} }
} }
impl S3Api for MakeBucket { impl S3Api for CreateBucket {
type S3Response = MakeBucketResponse; type S3Response = CreateBucketResponse;
} }
impl ToS3Request for MakeBucket { impl ToS3Request for CreateBucket {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
@ -95,8 +97,7 @@ impl ToS3Request for MakeBucket {
let data: String = match region_str.as_str() { let data: String = match region_str.as_str() {
DEFAULT_REGION => String::new(), DEFAULT_REGION => String::new(),
_ => format!( _ => format!(
"<CreateBucketConfiguration><LocationConstraint>{}</LocationConstraint></CreateBucketConfiguration>", "<CreateBucketConfiguration><LocationConstraint>{region_str}</LocationConstraint></CreateBucketConfiguration>",
region_str
), ),
}; };

View File

@ -15,22 +15,24 @@
use crate::s3::builders::BucketCommon; use crate::s3::builders::BucketCommon;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::response::RemoveBucketResponse; use crate::s3::response::DeleteBucketResponse;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::check_bucket_name; use crate::s3::utils::check_bucket_name;
use http::Method; use http::Method;
/// Argument builder for [remove_bucket()](Client::remove_bucket) API /// Argument builder for the [`GetBucketEncryption`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucket.html) S3 API operation.
pub type RemoveBucket = BucketCommon<RemoveBucketPhantomData>; ///
/// This struct constructs the parameters required for the [`Client::delete_bucket`](crate::s3::client::Client::delete_bucket) method.
pub type DeleteBucket = BucketCommon<DeleteBucketPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct RemoveBucketPhantomData; pub struct DeleteBucketPhantomData;
impl S3Api for RemoveBucket { impl S3Api for DeleteBucket {
type S3Response = RemoveBucketResponse; type S3Response = DeleteBucketResponse;
} }
impl ToS3Request for RemoveBucket { impl ToS3Request for DeleteBucket {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [delete_bucket_encryption()](Client::delete_bucket_encryption) API /// Argument builder for the [`DeleteBucketEncryption`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketEncryption.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::delete_bucket_encryption`](crate::s3::client::Client::delete_bucket_encryption) method.
pub type DeleteBucketEncryption = BucketCommon<DeleteBucketEncryptionPhantomData>; pub type DeleteBucketEncryption = BucketCommon<DeleteBucketEncryptionPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteBucketEncryptionPhantomData; pub struct DeleteBucketEncryptionPhantomData;
impl S3Api for DeleteBucketEncryption { impl S3Api for DeleteBucketEncryption {

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [delete_bucket_lifecycle()](Client::delete_bucket_lifecycle) API /// Argument builder for the [`DeleteBucketLifecycle`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::delete_bucket_lifecycle`](crate::s3::client::Client::delete_bucket_lifecycle) method.
pub type DeleteBucketLifecycle = BucketCommon<DeleteBucketLifecyclePhantomData>; pub type DeleteBucketLifecycle = BucketCommon<DeleteBucketLifecyclePhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteBucketLifecyclePhantomData; pub struct DeleteBucketLifecyclePhantomData;
impl S3Api for DeleteBucketLifecycle { impl S3Api for DeleteBucketLifecycle {

View File

@ -22,10 +22,10 @@ use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [delete_bucket_notification()](Client::delete_bucket_notification) API /// This struct constructs the parameters required for the [`Client::delete_bucket_notification`](crate::s3::client::Client::delete_bucket_notification) method.
pub type DeleteBucketNotification = BucketCommon<DeleteBucketNotificationPhantomData>; pub type DeleteBucketNotification = BucketCommon<DeleteBucketNotificationPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteBucketNotificationPhantomData; pub struct DeleteBucketNotificationPhantomData;
impl S3Api for DeleteBucketNotification { impl S3Api for DeleteBucketNotification {

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [delete_bucket_policy()](Client::delete_bucket_policy) API /// Argument builder for the [`DeleteBucketPolicy`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketPolicy.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::delete_bucket_policy`](crate::s3::client::Client::delete_bucket_policy) method.
pub type DeleteBucketPolicy = BucketCommon<DeleteBucketPolicyPhantomData>; pub type DeleteBucketPolicy = BucketCommon<DeleteBucketPolicyPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteBucketPolicyPhantomData; pub struct DeleteBucketPolicyPhantomData;
impl S3Api for DeleteBucketPolicy { impl S3Api for DeleteBucketPolicy {

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [delete_bucket_replication()](Client::delete_bucket_replication) API /// Argument builder for the [`DeleteBucketReplication`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketReplication.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::delete_bucket_replication`](crate::s3::client::Client::delete_bucket_replication) method.
pub type DeleteBucketReplication = BucketCommon<DeleteBucketReplicationPhantomData>; pub type DeleteBucketReplication = BucketCommon<DeleteBucketReplicationPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteBucketReplicationPhantomData; pub struct DeleteBucketReplicationPhantomData;
impl S3Api for DeleteBucketReplication { impl S3Api for DeleteBucketReplication {

View File

@ -15,22 +15,24 @@
use crate::s3::builders::BucketCommon; use crate::s3::builders::BucketCommon;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::response::DeleteBucketTagsResponse; use crate::s3::response::DeleteBucketTaggingResponse;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [delete_bucket_tags()](Client::delete_bucket_tags) API /// Argument builder for the [`DeleteBucketTagging`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketTagging.html) S3 API operation.
pub type DeleteBucketTags = BucketCommon<DeleteBucketTagsPhantomData>; ///
/// This struct constructs the parameters required for the [`Client::delete_bucket_tags`](crate::s3::client::Client::delete_bucket_tagging) method.
pub type DeleteBucketTagging = BucketCommon<DeleteBucketTaggingPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteBucketTagsPhantomData; pub struct DeleteBucketTaggingPhantomData;
impl S3Api for DeleteBucketTags { impl S3Api for DeleteBucketTagging {
type S3Response = DeleteBucketTagsResponse; type S3Response = DeleteBucketTaggingResponse;
} }
impl ToS3Request for DeleteBucketTags { impl ToS3Request for DeleteBucketTagging {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -22,10 +22,10 @@ use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [delete_object_lock_config()](Client::delete_object_lock_config) API /// This struct constructs the parameters required for the [`Client::delete_object_lock_config`](crate::s3::client::Client::delete_object_lock_config) method.
pub type DeleteObjectLockConfig = BucketCommon<DeleteObjectLockConfigPhantomData>; pub type DeleteObjectLockConfig = BucketCommon<DeleteObjectLockConfigPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct DeleteObjectLockConfigPhantomData; pub struct DeleteObjectLockConfigPhantomData;
impl S3Api for DeleteObjectLockConfig { impl S3Api for DeleteObjectLockConfig {

View File

@ -16,14 +16,16 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::DeleteObjectTagsResponse; use crate::s3::response::DeleteObjectTaggingResponse;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert}; use crate::s3::utils::{check_bucket_name, check_object_name, insert};
use http::Method; use http::Method;
/// Argument builder for [delete_object_tags()](Client::delete_object_tags) API /// Argument builder for the [`DeleteObjectTagging`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjectTagging.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::delete_object_tags`](crate::s3::client::Client::delete_object_tagging) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct DeleteObjectTags { pub struct DeleteObjectTagging {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -35,7 +37,7 @@ pub struct DeleteObjectTags {
version_id: Option<String>, version_id: Option<String>,
} }
impl DeleteObjectTags { impl DeleteObjectTagging {
pub fn new(client: Client, bucket: String, object: String) -> Self { pub fn new(client: Client, bucket: String, object: String) -> Self {
Self { Self {
client, client,
@ -66,11 +68,11 @@ impl DeleteObjectTags {
} }
} }
impl S3Api for DeleteObjectTags { impl S3Api for DeleteObjectTagging {
type S3Response = DeleteObjectTagsResponse; type S3Response = DeleteObjectTaggingResponse;
} }
impl ToS3Request for DeleteObjectTags { impl ToS3Request for DeleteObjectTagging {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
check_object_name(&self.object)?; check_object_name(&self.object)?;

View File

@ -1,5 +1,5 @@
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage // MinIO Rust Library for Amazon S3 Compatible Cloud Storage
// Copyright 2022-2024 MinIO, Inc. // Copyright 2025 MinIO, Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -273,7 +273,11 @@ impl ToS3Request for RemoveObjectsApi {
// endregion: remove-object-api // endregion: remove-object-api
// region: delete-object // region: delete-objects
/// Argument builder for the [`DeleteObjects`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteObjects.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::delete`](crate::s3::client::Client::get_bucket_encryption) method.
pub struct DeleteObjects { pub struct DeleteObjects {
items: Pin<Box<dyn Stream<Item = ObjectToDelete> + Send + Sync>>, items: Pin<Box<dyn Stream<Item = ObjectToDelete> + Send + Sync>>,
} }
@ -299,7 +303,7 @@ where
} }
} }
// endregion: delete-object // endregion: delete-objects
// region: remove-objects // region: remove-objects

View File

@ -1,92 +0,0 @@
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage
// Copyright 2025 MinIO, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::s3::Client;
use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::DisableObjectLegalHoldResponse;
use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert, md5sum_hash};
use bytes::Bytes;
use http::Method;
/// Argument builder for [disable_object_legal_hold()](Client::disable_object_legal_hold) API
#[derive(Clone, Debug, Default)]
pub struct DisableObjectLegalHold {
client: Client,
extra_headers: Option<Multimap>,
extra_query_params: Option<Multimap>,
region: Option<String>,
bucket: String,
object: String,
version_id: Option<String>,
}
impl DisableObjectLegalHold {
pub fn new(client: Client, bucket: String, object: String) -> Self {
Self {
client,
bucket,
object,
..Default::default()
}
}
pub fn extra_headers(mut self, extra_headers: Option<Multimap>) -> Self {
self.extra_headers = extra_headers;
self
}
pub fn extra_query_params(mut self, extra_query_params: Option<Multimap>) -> Self {
self.extra_query_params = extra_query_params;
self
}
pub fn version_id(mut self, version_id: Option<String>) -> Self {
self.version_id = version_id;
self
}
}
impl S3Api for DisableObjectLegalHold {
type S3Response = DisableObjectLegalHoldResponse;
}
impl ToS3Request for DisableObjectLegalHold {
fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?;
check_object_name(&self.object)?;
let mut headers: Multimap = self.extra_headers.unwrap_or_default();
let mut query_params: Multimap = insert(self.extra_query_params, "legal-hold");
query_params.add_version(self.version_id);
const PAYLOAD: &str = "<LegalHold><Status>OFF</Status></LegalHold>";
headers.add("Content-MD5", md5sum_hash(PAYLOAD.as_ref()));
let body: Option<SegmentedBytes> = Some(SegmentedBytes::from(Bytes::from(PAYLOAD)));
//TODO consider const body
Ok(S3Request::new(self.client, Method::PUT)
.region(self.region)
.bucket(Some(self.bucket))
.query_params(query_params)
.headers(headers)
.object(Some(self.object))
.body(body))
}
}

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_bucket_encryption()](crate::s3::client::Client::get_bucket_encryption) API /// Argument builder for the [`GetBucketEncryption`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketEncryption.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_encryption`](crate::s3::client::Client::get_bucket_encryption) method.
pub type GetBucketEncryption = BucketCommon<GetBucketEncryptionPhantomData>; pub type GetBucketEncryption = BucketCommon<GetBucketEncryptionPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct GetBucketEncryptionPhantomData; pub struct GetBucketEncryptionPhantomData;
impl S3Api for GetBucketEncryption { impl S3Api for GetBucketEncryption {

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_bucket_lifecycle()](Client::get_bucket_lifecycle) API /// Argument builder for the [`GetBucketLifecycle`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketLifecycle.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_lifecycle`](crate::s3::client::Client::get_bucket_lifecycle) method.
pub type GetBucketLifecycle = BucketCommon<GetBucketLifecyclePhantomData>; pub type GetBucketLifecycle = BucketCommon<GetBucketLifecyclePhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct GetBucketLifecyclePhantomData; pub struct GetBucketLifecyclePhantomData;
impl S3Api for GetBucketLifecycle { impl S3Api for GetBucketLifecycle {

View File

@ -20,7 +20,9 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_bucket_notification()](Client::get_bucket_notification) API /// Argument builder for the [`GetBucketNotification`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketNotification.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_notification`](crate::s3::client::Client::get_bucket_notification) method.
pub type GetBucketNotification = BucketCommon<GetBucketNotificationPhantomData>; pub type GetBucketNotification = BucketCommon<GetBucketNotificationPhantomData>;
#[derive(Default, Debug)] #[derive(Default, Debug)]

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_bucket_policy()](Client::get_bucket_policy) API /// Argument builder for the [`GetBucketPolicy`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketPolicy.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_policy`](crate::s3::client::Client::get_bucket_policy) method.
pub type GetBucketPolicy = BucketCommon<GetBucketPolicyPhantomData>; pub type GetBucketPolicy = BucketCommon<GetBucketPolicyPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct GetBucketPolicyPhantomData; pub struct GetBucketPolicyPhantomData;
impl S3Api for GetBucketPolicy { impl S3Api for GetBucketPolicy {

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_bucket_replication()](Client::get_bucket_replication) API /// Argument builder for the [`GetBucketReplication`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketReplication.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_replication`](crate::s3::client::Client::get_bucket_replication) method.
pub type GetBucketReplication = BucketCommon<GetBucketReplicationPhantomData>; pub type GetBucketReplication = BucketCommon<GetBucketReplicationPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct GetBucketReplicationPhantomData; pub struct GetBucketReplicationPhantomData;
impl S3Api for GetBucketReplication { impl S3Api for GetBucketReplication {

View File

@ -16,15 +16,17 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::GetBucketTagsResponse; use crate::s3::response::GetBucketTaggingResponse;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
use std::collections::HashMap; use std::collections::HashMap;
/// Argument builder for [get_bucket_tags()](crate::s3::client::Client::get_bucket_tags) API /// Argument builder for the [`GetBucketTagging`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketTagging.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_tagging`](crate::s3::client::Client::get_bucket_tagging) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct GetBucketTags { pub struct GetBucketTagging {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -35,7 +37,7 @@ pub struct GetBucketTags {
tags: HashMap<String, String>, tags: HashMap<String, String>,
} }
impl GetBucketTags { impl GetBucketTagging {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -65,11 +67,11 @@ impl GetBucketTags {
} }
} }
impl S3Api for GetBucketTags { impl S3Api for GetBucketTagging {
type S3Response = GetBucketTagsResponse; type S3Response = GetBucketTaggingResponse;
} }
impl ToS3Request for GetBucketTags { impl ToS3Request for GetBucketTagging {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_bucket_versioning()](crate::s3::client::Client::get_bucket_versioning) API /// Argument builder for the [`GetBucketVersioning`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetBucketVersioning.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_bucket_versioning`](crate::s3::client::Client::get_bucket_versioning) method.
pub type GetBucketVersioning = BucketCommon<GetBucketVersioningPhantomData>; pub type GetBucketVersioning = BucketCommon<GetBucketVersioningPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct GetBucketVersioningPhantomData; pub struct GetBucketVersioningPhantomData;
impl S3Api for GetBucketVersioning { impl S3Api for GetBucketVersioning {

View File

@ -26,7 +26,9 @@ use crate::s3::{
utils::{UtcTime, check_bucket_name, to_http_header_value}, utils::{UtcTime, check_bucket_name, to_http_header_value},
}; };
/// Argument builder for [list_objects()](Client::get_object) API. /// Argument builder for the [`GetObject`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObject.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_object`](crate::s3::client::Client::get_object) method.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct GetObject { pub struct GetObject {
client: Client, client: Client,

View File

@ -16,14 +16,16 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::IsObjectLegalHoldEnabledResponse; use crate::s3::response::GetObjectLegalHoldResponse;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert}; use crate::s3::utils::{check_bucket_name, check_object_name, insert};
use http::Method; use http::Method;
/// Argument builder for [is_object_legal_hold_enabled()](Client::is_object_legal_hold_enabled) API /// Argument builder for the [`GetObjectLegalHold`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLegalHold.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_object_legal_hold`](crate::s3::client::Client::get_object_legal_hold) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct IsObjectLegalHoldEnabled { pub struct GetObjectLegalHold {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -35,7 +37,7 @@ pub struct IsObjectLegalHoldEnabled {
version_id: Option<String>, version_id: Option<String>,
} }
impl IsObjectLegalHoldEnabled { impl GetObjectLegalHold {
pub fn new(client: Client, bucket: String, object: String) -> Self { pub fn new(client: Client, bucket: String, object: String) -> Self {
Self { Self {
client, client,
@ -61,11 +63,11 @@ impl IsObjectLegalHoldEnabled {
} }
} }
impl S3Api for IsObjectLegalHoldEnabled { impl S3Api for GetObjectLegalHold {
type S3Response = IsObjectLegalHoldEnabledResponse; type S3Response = GetObjectLegalHoldResponse;
} }
impl ToS3Request for IsObjectLegalHoldEnabled { impl ToS3Request for GetObjectLegalHold {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
check_object_name(&self.object)?; check_object_name(&self.object)?;

View File

@ -20,10 +20,12 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_object_lock_config()](Client::get_object_lock_config) API /// Argument builder for the [`GetObjectLockConfig`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectLockConfiguration.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_object_lock_config`](crate::s3::client::Client::get_object_lock_config) method.
pub type GetObjectLockConfig = BucketCommon<GetObjectLockConfigPhantomData>; pub type GetObjectLockConfig = BucketCommon<GetObjectLockConfigPhantomData>;
#[derive(Default, Debug)] #[derive(Clone, Debug, Default)]
pub struct GetObjectLockConfigPhantomData; pub struct GetObjectLockConfigPhantomData;
impl S3Api for GetObjectLockConfig { impl S3Api for GetObjectLockConfig {

View File

@ -20,7 +20,7 @@ use crate::s3::utils::{check_bucket_name, check_object_name};
use crate::s3::{ use crate::s3::{
client::Client, client::Client,
error::Error, error::Error,
response::ObjectPromptResponse, response::GetObjectPromptResponse,
types::{S3Api, S3Request, ToS3Request}, types::{S3Api, S3Request, ToS3Request},
}; };
use bytes::Bytes; use bytes::Bytes;
@ -28,7 +28,7 @@ use http::Method;
use serde_json::json; use serde_json::json;
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct ObjectPrompt { pub struct GetObjectPrompt {
client: Client, client: Client,
bucket: String, bucket: String,
object: String, object: String,
@ -43,9 +43,9 @@ pub struct ObjectPrompt {
} }
// builder interface // builder interface
impl ObjectPrompt { impl GetObjectPrompt {
pub fn new(client: Client, bucket: String, object: String, prompt: String) -> Self { pub fn new(client: Client, bucket: String, object: String, prompt: String) -> Self {
ObjectPrompt { GetObjectPrompt {
client, client,
bucket, bucket,
object, object,
@ -85,11 +85,11 @@ impl ObjectPrompt {
} }
} }
impl S3Api for ObjectPrompt { impl S3Api for GetObjectPrompt {
type S3Response = ObjectPromptResponse; type S3Response = GetObjectPromptResponse;
} }
impl ToS3Request for ObjectPrompt { impl ToS3Request for GetObjectPrompt {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
{ {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -21,7 +21,9 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert}; use crate::s3::utils::{check_bucket_name, check_object_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_object_retention()](Client::get_object_retention) API /// Argument builder for the [`GetObjectRetention`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_GetObjectRetention.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::get_object_retention`](crate::s3::client::Client::get_object_retention) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct GetObjectRetention { pub struct GetObjectRetention {
client: Client, client: Client,

View File

@ -16,14 +16,14 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::GetObjectTagsResponse; use crate::s3::response::GetObjectTaggingResponse;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert}; use crate::s3::utils::{check_bucket_name, check_object_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_object_tags()](Client::get_object_tags) API /// Argument builder for [get_object_tags()](crate::s3::client::Client::get_object_tagging) API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct GetObjectTags { pub struct GetObjectTagging {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -35,7 +35,7 @@ pub struct GetObjectTags {
version_id: Option<String>, version_id: Option<String>,
} }
impl GetObjectTags { impl GetObjectTagging {
pub fn new(client: Client, bucket: String, object: String) -> Self { pub fn new(client: Client, bucket: String, object: String) -> Self {
Self { Self {
client, client,
@ -66,11 +66,11 @@ impl GetObjectTags {
} }
} }
impl S3Api for GetObjectTags { impl S3Api for GetObjectTagging {
type S3Response = GetObjectTagsResponse; type S3Response = GetObjectTaggingResponse;
} }
impl ToS3Request for GetObjectTags { impl ToS3Request for GetObjectTagging {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
check_object_name(&self.object)?; check_object_name(&self.object)?;

View File

@ -23,7 +23,7 @@ use crate::s3::signer::presign_v4;
use crate::s3::utils::{UtcTime, check_bucket_name, check_object_name, utc_now}; use crate::s3::utils::{UtcTime, check_bucket_name, check_object_name, utc_now};
use http::Method; use http::Method;
/// Argument for [get_presigned_object_url()](crate::s3::client::Client::get_presigned_object_url) API /// This struct constructs the parameters required for the [`Client::get_presigned_object_url`](crate::s3::client::Client::get_presigned_object_url) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct GetPresignedObjectUrl { pub struct GetPresignedObjectUrl {
client: Client, client: Client,

View File

@ -23,7 +23,7 @@ use crate::s3::utils::{
use serde_json::{Value, json}; use serde_json::{Value, json};
use std::collections::HashMap; use std::collections::HashMap;
/// Argument for [get_presigned_object_url()](crate::s3::client::Client::get_presigned_object_url) API /// This struct constructs the parameters required for the [`Client::get_presigned_object_url`](crate::s3::client::Client::get_presigned_object_url) method.
pub struct GetPresignedPolicyFormData { pub struct GetPresignedPolicyFormData {
client: Client, client: Client,
policy: PostPolicy, policy: PostPolicy,
@ -54,6 +54,7 @@ impl GetPresignedPolicyFormData {
/// ///
/// Condition elements and respective condition for Post policy is available <a /// Condition elements and respective condition for Post policy is available <a
/// href="https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html#sigv4-PolicyConditions">here</a>. /// href="https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-HTTPPOSTConstructPolicy.html#sigv4-PolicyConditions">here</a>.
#[derive(Clone, Debug, Default)]
pub struct PostPolicy { pub struct PostPolicy {
pub region: Option<String>, pub region: Option<String>,
pub bucket: String, pub bucket: String,
@ -81,17 +82,13 @@ impl PostPolicy {
/// let expiration = utc_now() + Duration::days(7); /// let expiration = utc_now() + Duration::days(7);
/// let policy = PostPolicy::new("bucket-name", expiration).unwrap(); /// let policy = PostPolicy::new("bucket-name", expiration).unwrap();
/// ``` /// ```
pub fn new(bucket_name: &str, expiration: UtcTime) -> Result<PostPolicy, Error> { pub fn new(bucket_name: &str, expiration: UtcTime) -> Result<Self, Error> {
check_bucket_name(bucket_name, true)?; check_bucket_name(bucket_name, true)?;
Ok(PostPolicy { Ok(Self {
region: None,
bucket: bucket_name.to_owned(), bucket: bucket_name.to_owned(),
expiration, expiration,
eq_conditions: HashMap::new(), ..Default::default()
starts_with_conditions: HashMap::new(),
lower_limit: None,
upper_limit: None,
}) })
} }
@ -147,13 +144,12 @@ impl PostPolicy {
|| v.eq_ignore_ascii_case("content-length-range") || v.eq_ignore_ascii_case("content-length-range")
{ {
return Err(Error::PostPolicyError(format!( return Err(Error::PostPolicyError(format!(
"{} is unsupported for equals condition", "{element} is unsupported for equals condition",
element
))); )));
} }
if PostPolicy::is_reserved_element(v.as_str()) { if PostPolicy::is_reserved_element(v.as_str()) {
return Err(Error::PostPolicyError(format!("{} cannot set", element))); return Err(Error::PostPolicyError(format!("{element} cannot set")));
} }
self.eq_conditions.insert(v, value.to_string()); self.eq_conditions.insert(v, value.to_string());
@ -203,13 +199,12 @@ impl PostPolicy {
|| (v.starts_with("x-amz-") && v.starts_with("x-amz-meta-")) || (v.starts_with("x-amz-") && v.starts_with("x-amz-meta-"))
{ {
return Err(Error::PostPolicyError(format!( return Err(Error::PostPolicyError(format!(
"{} is unsupported for starts-with condition", "{element} is unsupported for starts-with condition",
element
))); )));
} }
if PostPolicy::is_reserved_element(v.as_str()) { if PostPolicy::is_reserved_element(v.as_str()) {
return Err(Error::PostPolicyError(format!("{} cannot set", element))); return Err(Error::PostPolicyError(format!("{element} cannot set")));
} }
self.starts_with_conditions.insert(v, value.to_string()); self.starts_with_conditions.insert(v, value.to_string());

View File

@ -22,7 +22,7 @@ use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use http::Method; use http::Method;
/// Argument builder for [get_region()](Client::get_region) API /// This struct constructs the parameters required for the [`Client::get_region`](crate::s3::client::Client::get_region) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct GetRegion { pub struct GetRegion {
client: Client, client: Client,

View File

@ -1,5 +1,5 @@
// MinIO Rust Library for Amazon S3 Compatible Cloud Storage // MinIO Rust Library for Amazon S3 Compatible Cloud Storage
// Copyright 2023 MinIO, Inc. // Copyright 2025 MinIO, Inc.
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License. // you may not use this file except in compliance with the License.
@ -21,16 +21,16 @@ use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::{ use crate::s3::{
client::Client, client::Client,
error::Error, error::Error,
response::ListenBucketNotificationResponse, response::ListBucketNotificationResponse,
types::{NotificationRecords, S3Api, S3Request, ToS3Request}, types::{NotificationRecords, S3Api, S3Request, ToS3Request},
utils::check_bucket_name, utils::check_bucket_name,
}; };
/// Argument builder for /// Argument builder for
/// [listen_bucket_notification()](crate::s3::client::Client::listen_bucket_notification) /// [listen_bucket_notification()](crate::s3::client::Client::list_bucket_notification)
/// API. /// API.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct ListenBucketNotification { pub struct ListBucketNotification {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -42,7 +42,7 @@ pub struct ListenBucketNotification {
events: Option<Vec<String>>, events: Option<Vec<String>>,
} }
impl ListenBucketNotification { impl ListBucketNotification {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -83,19 +83,19 @@ impl ListenBucketNotification {
} }
#[async_trait] #[async_trait]
impl S3Api for ListenBucketNotification { impl S3Api for ListBucketNotification {
type S3Response = ( type S3Response = (
ListenBucketNotificationResponse, ListBucketNotificationResponse,
Box<dyn Stream<Item = Result<NotificationRecords, Error>> + Unpin + Send>, Box<dyn Stream<Item = Result<NotificationRecords, Error>> + Unpin + Send>,
); );
} }
impl ToS3Request for ListenBucketNotification { impl ToS3Request for ListBucketNotification {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
{ {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
if self.client.is_aws_host() { if self.client.is_aws_host() {
return Err(Error::UnsupportedApi("ListenBucketNotification".into())); return Err(Error::UnsupportedApi("ListBucketNotification".into()));
} }
} }

View File

@ -23,7 +23,9 @@ use crate::s3::{
types::{S3Api, S3Request, ToS3Request}, types::{S3Api, S3Request, ToS3Request},
}; };
/// Argument builder for [list_buckets()](Client::list_buckets) API. /// Argument builder for the [`ListBuckets`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListBuckets.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::list_buckets`](crate::s3::client::Client::list_buckets) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct ListBuckets { pub struct ListBuckets {
client: Client, client: Client,

View File

@ -57,7 +57,9 @@ fn delim_helper(delim: Option<String>, recursive: bool) -> Option<String> {
// region: list-objects-v1 // region: list-objects-v1
/// Argument for ListObjectsV1 S3 API. /// Argument builder for the [`ListObjectsV1`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjects.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::list_objects`](crate::s3::client::Client::list_objects) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct ListObjectsV1 { struct ListObjectsV1 {
client: Client, client: Client,
@ -157,7 +159,9 @@ impl From<ListObjects> for ListObjectsV1 {
// region: list-objects-v2 // region: list-objects-v2
/// Argument for ListObjectsV2 S3 API. /// Argument builder for the [`ListObjectsV2`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::list_objects`](crate::s3::client::Client::list_objects) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct ListObjectsV2 { struct ListObjectsV2 {
client: Client, client: Client,
@ -174,7 +178,6 @@ struct ListObjectsV2 {
continuation_token: Option<String>, continuation_token: Option<String>,
fetch_owner: bool, fetch_owner: bool,
include_user_metadata: bool, include_user_metadata: bool,
unsorted: bool,
} }
#[async_trait] #[async_trait]
@ -241,9 +244,6 @@ impl ToS3Request for ListObjectsV2 {
if self.include_user_metadata { if self.include_user_metadata {
query_params.add("metadata", "true"); query_params.add("metadata", "true");
} }
if self.unsorted {
query_params.add("unsorted", "true");
}
} }
Ok(S3Request::new(self.client, Method::GET) Ok(S3Request::new(self.client, Method::GET)
@ -270,7 +270,6 @@ impl From<ListObjects> for ListObjectsV2 {
continuation_token: value.continuation_token, continuation_token: value.continuation_token,
fetch_owner: value.fetch_owner, fetch_owner: value.fetch_owner,
include_user_metadata: value.include_user_metadata, include_user_metadata: value.include_user_metadata,
unsorted: value.unsorted,
} }
} }
} }
@ -278,7 +277,9 @@ impl From<ListObjects> for ListObjectsV2 {
// region: list-object-versions // region: list-object-versions
/// Argument for ListObjectVersions S3 API /// Argument builder for the [`ListObjectVersions`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectVersions.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::list_objects`](crate::s3::client::Client::list_objects) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
struct ListObjectVersions { struct ListObjectVersions {
client: Client, client: Client,
@ -294,7 +295,6 @@ struct ListObjectVersions {
key_marker: Option<String>, key_marker: Option<String>,
version_id_marker: Option<String>, version_id_marker: Option<String>,
include_user_metadata: bool, include_user_metadata: bool,
unsorted: bool,
} }
#[async_trait] #[async_trait]
@ -361,9 +361,6 @@ impl ToS3Request for ListObjectVersions {
if self.include_user_metadata { if self.include_user_metadata {
query_params.add("metadata", "true"); query_params.add("metadata", "true");
} }
if self.unsorted {
query_params.add("unsorted", "true");
}
} }
Ok(S3Request::new(self.client, Method::GET) Ok(S3Request::new(self.client, Method::GET)
@ -389,7 +386,6 @@ impl From<ListObjects> for ListObjectVersions {
key_marker: value.key_marker, key_marker: value.key_marker,
version_id_marker: value.version_id_marker, version_id_marker: value.version_id_marker,
include_user_metadata: value.include_user_metadata, include_user_metadata: value.include_user_metadata,
unsorted: value.unsorted,
} }
} }
} }
@ -401,8 +397,8 @@ impl From<ListObjects> for ListObjectVersions {
/// Argument builder for /// Argument builder for
/// [list_objects()](crate::s3::client::Client::list_objects) API. /// [list_objects()](crate::s3::client::Client::list_objects) API.
/// ///
/// Use the various builder methods to set parameters on the request. Finally to /// Use the various builder methods to set parameters on the request. Finally, to
/// send the request and consume the results use the `ToStream` instance to get /// send the request and consume the results. Use the `ToStream` instance to get
/// a stream of results. Pagination is automatically performed. /// a stream of results. Pagination is automatically performed.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct ListObjects { pub struct ListObjects {
@ -435,7 +431,6 @@ pub struct ListObjects {
recursive: bool, recursive: bool,
use_api_v1: bool, use_api_v1: bool,
include_versions: bool, include_versions: bool,
unsorted: bool,
} }
#[async_trait] #[async_trait]
@ -486,7 +481,7 @@ impl ListObjects {
} }
/// Disable setting the `EncodingType` parameter in the ListObjects request. /// Disable setting the `EncodingType` parameter in the ListObjects request.
/// By default it is set to `url`. /// By default, it is set to `url`.
pub fn disable_url_encoding(mut self, disable_url_encoding: bool) -> Self { pub fn disable_url_encoding(mut self, disable_url_encoding: bool) -> Self {
self.disable_url_encoding = disable_url_encoding; self.disable_url_encoding = disable_url_encoding;
self self
@ -552,6 +547,10 @@ impl ListObjects {
} }
/// Set this to use ListObjectsV1. Defaults to false. /// Set this to use ListObjectsV1. Defaults to false.
/// * For general purpose buckets, ListObjectsV2 returns objects in
/// lexicographical order based on their key names.
/// * For directory buckets (S3-Express), ListObjectsV2 returns objects
/// in an unspecified order implementation-dependent order.
pub fn use_api_v1(mut self, use_api_v1: bool) -> Self { pub fn use_api_v1(mut self, use_api_v1: bool) -> Self {
self.use_api_v1 = use_api_v1; self.use_api_v1 = use_api_v1;
self self
@ -563,11 +562,5 @@ impl ListObjects {
self.include_versions = include_versions; self.include_versions = include_versions;
self self
} }
/// Set this to allow unsorted versions. Defaults to false
pub fn unsorted(mut self, unsorted: bool) -> Self {
self.unsorted = unsorted;
self
}
} }
// endregion: list-objects // endregion: list-objects

View File

@ -16,16 +16,16 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetBucketEncryptionResponse; use crate::s3::response::PutBucketEncryptionResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, SseConfig, ToS3Request}; use crate::s3::types::{S3Api, S3Request, SseConfig, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_bucket_encryption()](Client::set_bucket_encryption) API /// Argument builder for [put_bucket_encryption()](crate::s3::client::Client::put_bucket_encryption) API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketEncryption { pub struct PutBucketEncryption {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -36,7 +36,7 @@ pub struct SetBucketEncryption {
config: SseConfig, config: SseConfig,
} }
impl SetBucketEncryption { impl PutBucketEncryption {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -66,11 +66,11 @@ impl SetBucketEncryption {
} }
} }
impl S3Api for SetBucketEncryption { impl S3Api for PutBucketEncryption {
type S3Response = SetBucketEncryptionResponse; type S3Response = PutBucketEncryptionResponse;
} }
impl ToS3Request for SetBucketEncryption { impl ToS3Request for PutBucketEncryption {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,16 +16,16 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::SetBucketLifecycleResponse; use crate::s3::response::PutBucketLifecycleResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{LifecycleConfig, S3Api, S3Request, ToS3Request}; use crate::s3::types::{LifecycleConfig, S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert, md5sum_hash}; use crate::s3::utils::{check_bucket_name, insert, md5sum_hash};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_bucket_lifecycle()](crate::s3::client::Client::set_bucket_lifecycle) API /// Argument builder for [put_bucket_lifecycle()](crate::s3::client::Client::put_bucket_lifecycle) API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketLifecycle { pub struct PutBucketLifecycle {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -36,7 +36,7 @@ pub struct SetBucketLifecycle {
config: LifecycleConfig, config: LifecycleConfig,
} }
impl SetBucketLifecycle { impl PutBucketLifecycle {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -66,11 +66,11 @@ impl SetBucketLifecycle {
} }
} }
impl S3Api for SetBucketLifecycle { impl S3Api for PutBucketLifecycle {
type S3Response = SetBucketLifecycleResponse; type S3Response = PutBucketLifecycleResponse;
} }
impl ToS3Request for SetBucketLifecycle { impl ToS3Request for PutBucketLifecycle {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,16 +16,18 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetBucketNotificationResponse; use crate::s3::response::PutBucketNotificationResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{NotificationConfig, S3Api, S3Request, ToS3Request}; use crate::s3::types::{NotificationConfig, S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_bucket_notification()](crate::s3::client::Client::set_bucket_notification) API /// Argument builder for the [`PutBucketNotification`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketNotification.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_bucket_notification`](crate::s3::client::Client::put_bucket_notification) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketNotification { pub struct PutBucketNotification {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -36,7 +38,7 @@ pub struct SetBucketNotification {
config: NotificationConfig, config: NotificationConfig,
} }
impl SetBucketNotification { impl PutBucketNotification {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -66,11 +68,11 @@ impl SetBucketNotification {
} }
} }
impl S3Api for SetBucketNotification { impl S3Api for PutBucketNotification {
type S3Response = SetBucketNotificationResponse; type S3Response = PutBucketNotificationResponse;
} }
impl ToS3Request for SetBucketNotification { impl ToS3Request for PutBucketNotification {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,16 +16,18 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetBucketPolicyResponse; use crate::s3::response::PutBucketPolicyResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_bucket_policy()](crate::s3::client::Client::set_bucket_policy) API /// Argument builder for the [`PutBucketPolicy`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketPolicy.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_bucket_policy`](crate::s3::client::Client::put_bucket_policy) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketPolicy { pub struct PutBucketPolicy {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -36,7 +38,7 @@ pub struct SetBucketPolicy {
config: String, //TODO consider PolicyConfig struct config: String, //TODO consider PolicyConfig struct
} }
impl SetBucketPolicy { impl PutBucketPolicy {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -66,11 +68,11 @@ impl SetBucketPolicy {
} }
} }
impl S3Api for SetBucketPolicy { impl S3Api for PutBucketPolicy {
type S3Response = SetBucketPolicyResponse; type S3Response = PutBucketPolicyResponse;
} }
impl ToS3Request for SetBucketPolicy { impl ToS3Request for PutBucketPolicy {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,16 +16,18 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetBucketReplicationResponse; use crate::s3::response::PutBucketReplicationResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{ReplicationConfig, S3Api, S3Request, ToS3Request}; use crate::s3::types::{ReplicationConfig, S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_bucket_replication()](crate::s3::client::Client::set_bucket_replication) API /// Argument builder for the [`PutBucketReplication`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketReplication.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_bucket_replication`](crate::s3::client::Client::put_bucket_replication) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketReplication { pub struct PutBucketReplication {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -36,7 +38,7 @@ pub struct SetBucketReplication {
config: ReplicationConfig, config: ReplicationConfig,
} }
impl SetBucketReplication { impl PutBucketReplication {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -66,11 +68,11 @@ impl SetBucketReplication {
} }
} }
impl S3Api for SetBucketReplication { impl S3Api for PutBucketReplication {
type S3Response = SetBucketReplicationResponse; type S3Response = PutBucketReplicationResponse;
} }
impl ToS3Request for SetBucketReplication { impl ToS3Request for PutBucketReplication {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,7 +16,7 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetBucketTagsResponse; use crate::s3::response::PutBucketTaggingResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
@ -24,9 +24,11 @@ use bytes::Bytes;
use http::Method; use http::Method;
use std::collections::HashMap; use std::collections::HashMap;
/// Argument builder for [set_bucket_tags()](crate::s3::client::Client::set_bucket_tags) API /// Argument builder for the [`PutBucketTagging`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketTagging.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_bucket_tagging`](crate::s3::client::Client::put_bucket_tagging) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketTags { pub struct PutBucketTagging {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -37,7 +39,7 @@ pub struct SetBucketTags {
tags: HashMap<String, String>, tags: HashMap<String, String>,
} }
impl SetBucketTags { impl PutBucketTagging {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -67,11 +69,11 @@ impl SetBucketTags {
} }
} }
impl S3Api for SetBucketTags { impl S3Api for PutBucketTagging {
type S3Response = SetBucketTagsResponse; type S3Response = PutBucketTaggingResponse;
} }
impl ToS3Request for SetBucketTags { impl ToS3Request for PutBucketTagging {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,7 +16,7 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetBucketVersioningResponse; use crate::s3::response::PutBucketVersioningResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
@ -24,11 +24,20 @@ use bytes::Bytes;
use http::Method; use http::Method;
use std::fmt; use std::fmt;
/// Represents the versioning state of an S3 bucket.
///
/// This enum corresponds to the possible values returned by the
/// `GetBucketVersioning` API call in S3-compatible services.
///
/// # Variants
///
/// - `Enabled`: Object versioning is enabled for the bucket.
/// - `Suspended`: Object versioning is suspended for the bucket.
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum VersioningStatus { pub enum VersioningStatus {
/// **Enable** object versioning in given bucket. /// Object versioning is enabled for the bucket.
Enabled, Enabled,
/// **Suspend** object versioning in given bucket. /// Object versioning is suspended for the bucket.
Suspended, Suspended,
} }
@ -41,21 +50,42 @@ impl fmt::Display for VersioningStatus {
} }
} }
/// Argument builder for [set_bucket_encryption()](crate::s3::client::Client::set_bucket_encryption) API /// Argument builder for the [`PutBucketVersioning`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketVersioning.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_bucket_versioning`](crate::s3::client::Client::put_bucket_versioning) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetBucketVersioning { pub struct PutBucketVersioning {
/// The S3 client instance used to send the request.
client: Client, client: Client,
/// Optional additional HTTP headers to include in the request.
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
/// Optional additional query parameters to include in the request URL.
extra_query_params: Option<Multimap>, extra_query_params: Option<Multimap>,
/// Optional AWS region to override the client's default region.
region: Option<String>, region: Option<String>,
/// The name of the bucket for which to configure versioning.
bucket: String, bucket: String,
/// Desired versioning status for the bucket.
///
/// - `Some(VersioningStatus::Enabled)`: Enables versioning.
/// - `Some(VersioningStatus::Suspended)`: Suspends versioning.
/// - `None`: No change to the current versioning status.
status: Option<VersioningStatus>, status: Option<VersioningStatus>,
/// Specifies whether MFA delete is enabled for the bucket.
///
/// - `Some(true)`: Enables MFA delete.
/// - `Some(false)`: Disables MFA delete.
/// - `None`: No change to the current MFA delete setting.
mfa_delete: Option<bool>, mfa_delete: Option<bool>,
} }
impl SetBucketVersioning { impl PutBucketVersioning {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -90,11 +120,11 @@ impl SetBucketVersioning {
} }
} }
impl S3Api for SetBucketVersioning { impl S3Api for PutBucketVersioning {
type S3Response = SetBucketVersioningResponse; type S3Response = PutBucketVersioningResponse;
} }
impl ToS3Request for SetBucketVersioning { impl ToS3Request for PutBucketVersioning {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -36,7 +36,7 @@ use std::{collections::HashMap, sync::Arc};
// region: multipart-upload // region: multipart-upload
/// Argument for /// Argument for
/// [create_multipart_upload()](Client::create_multipart_upload) /// [create_multipart_upload()](crate::s3::client::Client::create_multipart_upload)
/// API /// API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct CreateMultipartUpload { pub struct CreateMultipartUpload {
@ -145,7 +145,7 @@ impl ToS3Request for CreateMultipartUpload {
// region: abort-multipart-upload // region: abort-multipart-upload
/// Argument for /// Argument for
/// [abort_multipart_upload()](Client::abort_multipart_upload) /// [abort_multipart_upload()](crate::s3::client::Client::abort_multipart_upload)
/// API /// API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct AbortMultipartUpload { pub struct AbortMultipartUpload {
@ -214,7 +214,7 @@ impl ToS3Request for AbortMultipartUpload {
// region: complete-multipart-upload // region: complete-multipart-upload
/// Argument for /// Argument for
/// [complete_multipart_upload()](Client::complete_multipart_upload) /// [complete_multipart_upload()](crate::s3::client::Client::complete_multipart_upload)
/// API /// API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct CompleteMultipartUpload { pub struct CompleteMultipartUpload {
@ -317,7 +317,7 @@ impl ToS3Request for CompleteMultipartUpload {
// region: upload-part // region: upload-part
/// Argument for [upload_part()](Client::upload_part) S3 API /// Argument for [upload_part()](crate::s3::client::Client::upload_part) S3 API
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct UploadPart { pub struct UploadPart {
client: Client, client: Client,
@ -417,8 +417,7 @@ impl ToS3Request for UploadPart {
if let Some(part_number) = self.part_number { if let Some(part_number) = self.part_number {
if !(1..=MAX_MULTIPART_COUNT).contains(&part_number) { if !(1..=MAX_MULTIPART_COUNT).contains(&part_number) {
return Err(Error::InvalidPartNumber(format!( return Err(Error::InvalidPartNumber(format!(
"part number must be between 1 and {}", "part number must be between 1 and {MAX_MULTIPART_COUNT}"
MAX_MULTIPART_COUNT
))); )));
} }
} }
@ -530,6 +529,7 @@ impl ToS3Request for PutObject {
/// PutObjectContent takes a `ObjectContent` stream and uploads it to MinIO/S3. /// PutObjectContent takes a `ObjectContent` stream and uploads it to MinIO/S3.
/// ///
/// It is a higher level API and handles multipart uploads transparently. /// It is a higher level API and handles multipart uploads transparently.
#[derive(Default)]
pub struct PutObjectContent { pub struct PutObjectContent {
client: Client, client: Client,
@ -567,18 +567,7 @@ impl PutObjectContent {
bucket, bucket,
object, object,
input_content: content.into(), input_content: content.into(),
extra_headers: None, ..Default::default()
extra_query_params: None,
region: None,
user_metadata: None,
sse: None,
tags: None,
retention: None,
legal_hold: false,
part_size: Size::Unknown,
content_type: None,
content_stream: ContentStream::empty(),
part_count: None,
} }
} }
@ -777,12 +766,7 @@ impl PutObjectContent {
let buffer_size = part_content.len() as u64; let buffer_size = part_content.len() as u64;
total_read += buffer_size; total_read += buffer_size;
assert!( assert!(buffer_size <= part_size, "{buffer_size} <= {part_size}",);
buffer_size <= part_size,
"{:?} <= {:?}",
buffer_size,
part_size
);
if (buffer_size == 0) && (part_number > 1) { if (buffer_size == 0) && (part_number > 1) {
// We are done as we uploaded at least 1 part and we have reached the end of the stream. // We are done as we uploaded at least 1 part and we have reached the end of the stream.
@ -897,8 +881,7 @@ fn into_headers_put_object(
} }
if !k.starts_with("x-amz-meta-") { if !k.starts_with("x-amz-meta-") {
return Err(Error::InvalidUserMetadata(format!( return Err(Error::InvalidUserMetadata(format!(
"user metadata key '{}' does not start with 'x-amz-meta-'", "user metadata key '{k}' does not start with 'x-amz-meta-'",
k
))); )));
} }
} }
@ -941,10 +924,7 @@ fn into_headers_put_object(
if !map.contains_key("Content-Type") { if !map.contains_key("Content-Type") {
map.insert( map.insert(
"Content-Type".into(), "Content-Type".into(),
match content_type { content_type.unwrap_or_else(|| "application/octet-stream".into()),
Some(content_type) => content_type.clone(),
None => "application/octet-stream".into(),
},
); );
} }

View File

@ -16,16 +16,18 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::EnableObjectLegalHoldResponse; use crate::s3::response::PutObjectLegalHoldResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert, md5sum_hash}; use crate::s3::utils::{check_bucket_name, check_object_name, insert, md5sum_hash};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [enable_object_legal_hold()](Client::enable_object_legal_hold) API /// Argument builder for the [`PutObjectLegalHold`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLegalHold.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_object_legal_hold`](crate::s3::client::Client::put_object_legal_hold) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct EnableObjectLegalHold { pub struct PutObjectLegalHold {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -35,9 +37,10 @@ pub struct EnableObjectLegalHold {
object: String, object: String,
version_id: Option<String>, version_id: Option<String>,
legal_hold: Option<bool>,
} }
impl EnableObjectLegalHold { impl PutObjectLegalHold {
pub fn new(client: Client, bucket: String, object: String) -> Self { pub fn new(client: Client, bucket: String, object: String) -> Self {
Self { Self {
client, client,
@ -61,13 +64,18 @@ impl EnableObjectLegalHold {
self.version_id = version_id; self.version_id = version_id;
self self
} }
pub fn legal_hold(mut self, legal_hold: Option<bool>) -> Self {
self.legal_hold = legal_hold;
self
}
} }
impl S3Api for EnableObjectLegalHold { impl S3Api for PutObjectLegalHold {
type S3Response = EnableObjectLegalHoldResponse; type S3Response = PutObjectLegalHoldResponse;
} }
impl ToS3Request for EnableObjectLegalHold { impl ToS3Request for PutObjectLegalHold {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
check_object_name(&self.object)?; check_object_name(&self.object)?;
@ -76,10 +84,14 @@ impl ToS3Request for EnableObjectLegalHold {
let mut query_params: Multimap = insert(self.extra_query_params, "legal-hold"); let mut query_params: Multimap = insert(self.extra_query_params, "legal-hold");
query_params.add_version(self.version_id); query_params.add_version(self.version_id);
const PAYLOAD: &str = "<LegalHold><Status>ON</Status></LegalHold>"; let payload: &str = match self.legal_hold {
headers.add("Content-MD5", md5sum_hash(PAYLOAD.as_ref())); Some(true) => "<LegalHold><Status>ON</Status></LegalHold>",
let body: Option<SegmentedBytes> = Some(SegmentedBytes::from(Bytes::from(PAYLOAD))); _ => "<LegalHold><Status>OFF</Status></LegalHold>",
//TODO consider const body };
// TODO consider const payload with precalculated md5
headers.add("Content-MD5", md5sum_hash(payload.as_ref()));
let body: Option<SegmentedBytes> = Some(SegmentedBytes::from(Bytes::from(payload)));
Ok(S3Request::new(self.client, Method::PUT) Ok(S3Request::new(self.client, Method::PUT)
.region(self.region) .region(self.region)

View File

@ -16,17 +16,18 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::Multimap; use crate::s3::multimap::Multimap;
use crate::s3::response::SetObjectLockConfigResponse; use crate::s3::response::PutObjectLockConfigResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{ObjectLockConfig, S3Api, S3Request, ToS3Request}; use crate::s3::types::{ObjectLockConfig, S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, insert}; use crate::s3::utils::{check_bucket_name, insert};
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_object_lock_config()](Client::set_object_lock_config) API /// Argument builder for the [`PutObjectLockConfig`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectLockConfiguration.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_object_lock_config`](crate::s3::client::Client::put_object_lock_config) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetObjectLockConfig { pub struct PutObjectLockConfig {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -37,7 +38,7 @@ pub struct SetObjectLockConfig {
config: ObjectLockConfig, config: ObjectLockConfig,
} }
impl SetObjectLockConfig { impl PutObjectLockConfig {
pub fn new(client: Client, bucket: String) -> Self { pub fn new(client: Client, bucket: String) -> Self {
Self { Self {
client, client,
@ -67,11 +68,11 @@ impl SetObjectLockConfig {
} }
} }
impl S3Api for SetObjectLockConfig { impl S3Api for PutObjectLockConfig {
type S3Response = SetObjectLockConfigResponse; type S3Response = PutObjectLockConfigResponse;
} }
impl ToS3Request for SetObjectLockConfig { impl ToS3Request for PutObjectLockConfig {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,7 +16,7 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::SetObjectRetentionResponse; use crate::s3::response::PutObjectRetentionResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{RetentionMode, S3Api, S3Request, ToS3Request}; use crate::s3::types::{RetentionMode, S3Api, S3Request, ToS3Request};
use crate::s3::utils::{ use crate::s3::utils::{
@ -25,9 +25,11 @@ use crate::s3::utils::{
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [set_object_retention()](Client::set_object_retention) API /// Argument builder for the [`PutObjectRetention`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutObjectRetention.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::put_object_retention`](crate::s3::client::Client::put_object_retention) method.
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetObjectRetention { pub struct PutObjectRetention {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -42,7 +44,7 @@ pub struct SetObjectRetention {
retain_until_date: Option<UtcTime>, retain_until_date: Option<UtcTime>,
} }
impl SetObjectRetention { impl PutObjectRetention {
pub fn new(client: Client, bucket: String, object: String) -> Self { pub fn new(client: Client, bucket: String, object: String) -> Self {
Self { Self {
client, client,
@ -88,11 +90,11 @@ impl SetObjectRetention {
} }
} }
impl S3Api for SetObjectRetention { impl S3Api for PutObjectRetention {
type S3Response = SetObjectRetentionResponse; type S3Response = PutObjectRetentionResponse;
} }
impl ToS3Request for SetObjectRetention { impl ToS3Request for PutObjectRetention {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
{ {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;

View File

@ -16,7 +16,7 @@
use crate::s3::Client; use crate::s3::Client;
use crate::s3::error::Error; use crate::s3::error::Error;
use crate::s3::multimap::{Multimap, MultimapExt}; use crate::s3::multimap::{Multimap, MultimapExt};
use crate::s3::response::SetObjectTagsResponse; use crate::s3::response::PutObjectTaggingResponse;
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
use crate::s3::types::{S3Api, S3Request, ToS3Request}; use crate::s3::types::{S3Api, S3Request, ToS3Request};
use crate::s3::utils::{check_bucket_name, check_object_name, insert}; use crate::s3::utils::{check_bucket_name, check_object_name, insert};
@ -24,9 +24,9 @@ use bytes::Bytes;
use http::Method; use http::Method;
use std::collections::HashMap; use std::collections::HashMap;
/// Argument builder for [set_object_tags()](Client::set_object_tags) API /// Argument builder for [put_object_tagging()](crate::s3::client::Client::put_object_tagging) API
#[derive(Clone, Debug, Default)] #[derive(Clone, Debug, Default)]
pub struct SetObjectTags { pub struct PutObjectTagging {
client: Client, client: Client,
extra_headers: Option<Multimap>, extra_headers: Option<Multimap>,
@ -39,7 +39,7 @@ pub struct SetObjectTags {
tags: HashMap<String, String>, tags: HashMap<String, String>,
} }
impl SetObjectTags { impl PutObjectTagging {
pub fn new(client: Client, bucket: String, object: String) -> Self { pub fn new(client: Client, bucket: String, object: String) -> Self {
Self { Self {
client, client,
@ -75,11 +75,11 @@ impl SetObjectTags {
} }
} }
impl S3Api for SetObjectTags { impl S3Api for PutObjectTagging {
type S3Response = SetObjectTagsResponse; type S3Response = PutObjectTaggingResponse;
} }
impl ToS3Request for SetObjectTags { impl ToS3Request for PutObjectTagging {
fn to_s3request(self) -> Result<S3Request, Error> { fn to_s3request(self) -> Result<S3Request, Error> {
check_bucket_name(&self.bucket, true)?; check_bucket_name(&self.bucket, true)?;
check_object_name(&self.object)?; check_object_name(&self.object)?;

View File

@ -25,7 +25,9 @@ use async_trait::async_trait;
use bytes::Bytes; use bytes::Bytes;
use http::Method; use http::Method;
/// Argument builder for [bucket_exists()](Client::bucket_exists) API /// Argument builder for the [`SelectObjectContent`](https://docs.aws.amazon.com/AmazonS3/latest/API/API_SelectObjectContent.html) S3 API operation.
///
/// This struct constructs the parameters required for the [`Client::select_object_content`](crate::s3::client::Client::select_object_content) method.
#[derive(Default)] #[derive(Default)]
pub struct SelectObjectContent { pub struct SelectObjectContent {
client: Client, client: Client,

View File

@ -27,7 +27,7 @@ use crate::s3::{
utils::{UtcTime, check_bucket_name, to_http_header_value}, utils::{UtcTime, check_bucket_name, to_http_header_value},
}; };
/// Argument builder for [list_objects()](Client::get_object) API. /// This struct constructs the parameters required for the [`Client::stat_object`](crate::s3::client::Client::stat_object) method.
#[derive(Debug, Clone, Default)] #[derive(Debug, Clone, Default)]
pub struct StatObject { pub struct StatObject {
client: Client, client: Client,

View File

@ -43,50 +43,49 @@ use tokio::task;
mod append_object; mod append_object;
mod bucket_exists; mod bucket_exists;
mod copy_object; mod copy_object;
mod create_bucket;
mod delete_bucket;
mod delete_bucket_encryption; mod delete_bucket_encryption;
mod delete_bucket_lifecycle; mod delete_bucket_lifecycle;
mod delete_bucket_notification; mod delete_bucket_notification;
mod delete_bucket_policy; mod delete_bucket_policy;
mod delete_bucket_replication; mod delete_bucket_replication;
mod delete_bucket_tags; mod delete_bucket_tagging;
mod delete_object_lock_config; mod delete_object_lock_config;
mod delete_object_tags; mod delete_object_tagging;
mod disable_object_legal_hold; mod delete_objects;
mod enable_object_legal_hold;
mod get_bucket_encryption; mod get_bucket_encryption;
mod get_bucket_lifecycle; mod get_bucket_lifecycle;
mod get_bucket_notification; mod get_bucket_notification;
mod get_bucket_policy; mod get_bucket_policy;
mod get_bucket_replication; mod get_bucket_replication;
mod get_bucket_tags; mod get_bucket_tagging;
mod get_bucket_versioning; mod get_bucket_versioning;
mod get_object; mod get_object;
mod get_object_legal_hold;
mod get_object_lock_config; mod get_object_lock_config;
mod get_object_prompt;
mod get_object_retention; mod get_object_retention;
mod get_object_tags; mod get_object_tagging;
mod get_presigned_object_url; mod get_presigned_object_url;
mod get_presigned_post_form_data; mod get_presigned_post_form_data;
mod get_region; mod get_region;
mod is_object_legal_hold_enabled; mod list_bucket_notification;
mod list_buckets; mod list_buckets;
mod list_objects; mod list_objects;
mod listen_bucket_notification; mod put_bucket_encryption;
mod make_bucket; mod put_bucket_lifecycle;
mod object_prompt; mod put_bucket_notification;
mod put_bucket_policy;
mod put_bucket_replication;
mod put_bucket_tagging;
mod put_bucket_versioning;
mod put_object; mod put_object;
mod remove_bucket; mod put_object_legal_hold;
mod remove_objects; mod put_object_lock_config;
mod put_object_retention;
mod put_object_tagging;
mod select_object_content; mod select_object_content;
mod set_bucket_encryption;
mod set_bucket_lifecycle;
mod set_bucket_notification;
mod set_bucket_policy;
mod set_bucket_replication;
mod set_bucket_tags;
mod set_bucket_versioning;
mod set_object_lock_config;
mod set_object_retention;
mod set_object_tags;
mod stat_object; mod stat_object;
use super::types::S3Api; use super::types::S3Api;
@ -252,7 +251,7 @@ impl Client {
/// Returns whether this client is configured to use the express endpoint and is minio enterprise. /// Returns whether this client is configured to use the express endpoint and is minio enterprise.
pub fn is_minio_express(&self) -> bool { pub fn is_minio_express(&self) -> bool {
if self.shared.express.get().is_some() { if self.shared.express.get().is_some() {
self.shared.express.get().unwrap().clone() *self.shared.express.get().unwrap()
} else { } else {
task::block_in_place(|| match tokio::runtime::Runtime::new() { task::block_in_place(|| match tokio::runtime::Runtime::new() {
Ok(rt) => { Ok(rt) => {
@ -483,12 +482,8 @@ impl Client {
// Sort headers alphabetically by name // Sort headers alphabetically by name
header_strings.sort(); header_strings.sort();
let body_str: String = String::from_utf8( let body_str: String =
body.clone() String::from_utf8(body.unwrap_or(&SegmentedBytes::new()).to_bytes().to_vec())?;
.unwrap_or(&SegmentedBytes::new())
.to_bytes()
.to_vec(),
)?;
println!( println!(
"S3 request: {} url={:?}; headers={:?}; body={}\n", "S3 request: {} url={:?}; headers={:?}; body={}\n",
@ -535,15 +530,12 @@ impl Client {
retry, retry,
); );
match e { if let Error::S3Error(ref err) = e {
Error::S3Error(ref err) => { if (err.code == ErrorCode::NoSuchBucket) || (err.code == ErrorCode::RetryHead) {
if (err.code == ErrorCode::NoSuchBucket) || (err.code == ErrorCode::RetryHead) { if let Some(v) = bucket_name {
if let Some(v) = bucket_name { self.shared.region_map.remove(v);
self.shared.region_map.remove(v);
}
} }
} }
_ => {}
}; };
Err(e) Err(e)
@ -700,12 +692,12 @@ impl SharedClientItems {
409 => match bucket_name { 409 => match bucket_name {
Some(_) => (ErrorCode::NoSuchBucket, "Bucket does not exist".into()), Some(_) => (ErrorCode::NoSuchBucket, "Bucket does not exist".into()),
_ => ( _ => (
ErrorCode::ResourceConflict.into(), ErrorCode::ResourceConflict,
"Request resource conflicts".into(), "Request resource conflicts".into(),
), ),
}, },
501 => ( 501 => (
ErrorCode::MethodNotAllowed.into(), ErrorCode::MethodNotAllowed,
"The specified method is not allowed against this resource".into(), "The specified method is not allowed against this resource".into(),
), ),
_ => return Error::ServerError(http_status_code), _ => return Error::ServerError(http_status_code),

View File

@ -21,14 +21,41 @@ use crate::s3::builders::{AppendObject, AppendObjectContent};
use crate::s3::segmented_bytes::SegmentedBytes; use crate::s3::segmented_bytes::SegmentedBytes;
impl Client { impl Client {
/// Creates an AppendObject request builder to append data to the end of an (existing) object. /// Creates a [`AppendObject`] request builder to append data to the end of an (existing) object.
/// This is a lower-level API that performs a non-multipart object upload. /// This is a lower-level API that performs a non-multipart object upload.
/// ///
/// To execute the request, call [`AppendObject::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`AppendObjectResponse`](crate::s3::response::AppendObjectResponse).
///
/// 🛈 This operation is not supported for regular non-express buckets. /// 🛈 This operation is not supported for regular non-express buckets.
pub fn append_object<S1: Into<String>, S2: Into<String>>( ///
/// # Example
///
/// ```no_run
/// use minio::s3::Client;
/// use minio::s3::response::{AppendObjectResponse, PutObjectResponse};
/// use minio::s3::segmented_bytes::SegmentedBytes;
/// use minio::s3::types::S3Api;
///
/// #[tokio::main]
/// async fn main() {
/// let client: Client = Default::default(); // configure your client here
/// let data1: SegmentedBytes = SegmentedBytes::from("aaaa".to_string());
/// let data2: SegmentedBytes = SegmentedBytes::from("bbbb".to_string());
/// let resp: PutObjectResponse = client
/// .put_object("bucket-name", "object-name", data1)
/// .send().await.unwrap();
/// let offset_bytes = 4; // the offset at which to append the data
/// let resp: AppendObjectResponse = client
/// .append_object("bucket-name", "object-name", data2, offset_bytes)
/// .send().await.unwrap();
/// println!("size of the final object is {} bytes", resp.object_size);
/// }
/// ```
pub fn append_object<S: Into<String>>(
&self, &self,
bucket: S1, bucket: S,
object: S2, object: S,
data: SegmentedBytes, data: SegmentedBytes,
offset_bytes: u64, offset_bytes: u64,
) -> AppendObject { ) -> AppendObject {
@ -41,13 +68,42 @@ impl Client {
) )
} }
/// Creates an AppendObjectContent request builder to append data to the end of an existing /// Creates an [`AppendObjectContent`] request builder to append data to the end of an (existing)
/// object. The content is streamed and appended to MinIO/S3. This is a higher-level API that /// object. The content is streamed and appended to MinIO/S3. This is a higher-level API that
/// handles multipart appends transparently. /// handles multipart appends transparently.
pub fn append_object_content<S1: Into<String>, S2: Into<String>, C: Into<ObjectContent>>( ///
/// To execute the request, call [`AppendObjectContent::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`AppendObjectResponse`](crate::s3::response::AppendObjectResponse).
///
/// 🛈 This operation is not supported for regular non-express buckets.
///
/// # Example
///
/// ```no_run
/// use minio::s3::Client;
/// use minio::s3::response::{AppendObjectResponse, PutObjectResponse};
/// use minio::s3::builders::ObjectContent;
/// use minio::s3::segmented_bytes::SegmentedBytes;
/// use minio::s3::types::S3Api;
///
/// #[tokio::main]
/// async fn main() {
/// let client: Client = Default::default(); // configure your client here
/// let data1: SegmentedBytes = SegmentedBytes::from("aaaa".to_string());
/// let content2: String = "bbbb".to_string();
/// let resp: PutObjectResponse = client
/// .put_object("bucket-name", "object-name", data1)
/// .send().await.unwrap();
/// let resp: AppendObjectResponse = client
/// .append_object_content("bucket-name", "object-name", content2)
/// .send().await.unwrap();
/// println!("size of the final object is {} bytes", resp.object_size);
/// }
/// ```
pub fn append_object_content<S: Into<String>, C: Into<ObjectContent>>(
&self, &self,
bucket: S1, bucket: S,
object: S2, object: S,
content: C, content: C,
) -> AppendObjectContent { ) -> AppendObjectContent {
AppendObjectContent::new(self.clone(), bucket.into(), object.into(), content) AppendObjectContent::new(self.clone(), bucket.into(), object.into(), content)

View File

@ -31,12 +31,12 @@ impl Client {
/// use minio::s3::response::BucketExistsResponse; /// use minio::s3::response::BucketExistsResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: BucketExistsResponse = /// let resp: BucketExistsResponse = client
/// client.bucket_exists("bucket-name").send().await.unwrap(); /// .bucket_exists("bucket-name")
/// .send().await.unwrap();
/// println!("bucket '{}' exists: {}", resp.bucket, resp.exists); /// println!("bucket '{}' exists: {}", resp.bucket, resp.exists);
/// } /// }
/// ``` /// ```

View File

@ -22,7 +22,31 @@ use crate::s3::builders::{
}; };
impl Client { impl Client {
/// Executes [UploadPartCopy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html) S3 API /// Creates a [`UploadPartCopy`] request builder.
/// See [UploadPartCopy](https://docs.aws.amazon.com/AmazonS3/latest/API/API_UploadPartCopy.html) S3 API
///
/// To execute the request, call [`UploadPartCopy::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`UploadPartCopyResponse`](crate::s3::response::UploadPartCopyResponse).
///
/// # Example
///
/// ```no_run
/// use minio::s3::Client;
/// use minio::s3::response::{UploadPartCopyResponse};
/// use minio::s3::segmented_bytes::SegmentedBytes;
/// use minio::s3::types::S3Api;
///
/// #[tokio::main]
/// async fn main() {
/// let client: Client = Default::default(); // configure your client here
/// let data1: SegmentedBytes = SegmentedBytes::from("aaaa".to_string());
/// todo!();
/// let resp: UploadPartCopyResponse = client
/// .upload_part_copy("bucket-name", "object-name", "TODO")
/// .send().await.unwrap();
/// println!("uploaded {}", resp.object);
/// }
/// ```
pub fn upload_part_copy<S1: Into<String>, S2: Into<String>, S3: Into<String>>( pub fn upload_part_copy<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,
@ -34,7 +58,7 @@ impl Client {
/// Create a CopyObject request builder. This is a lower-level API that /// Create a CopyObject request builder. This is a lower-level API that
/// performs a non-multipart object copy. /// performs a non-multipart object copy.
pub fn copy_object_internal<S1: Into<String>, S2: Into<String>>( pub(crate) fn copy_object_internal<S1: Into<String>, S2: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,
object: S2, object: S2,
@ -42,8 +66,8 @@ impl Client {
CopyObjectInternal::new(self.clone(), bucket.into(), object.into()) CopyObjectInternal::new(self.clone(), bucket.into(), object.into())
} }
/// copy object is a high-order API that calls [`stat_object`] and based on the results calls /// copy object is a high-order API that calls [stat_object](Client::stat_object) and based on the results calls
/// either [`compose_object`] or [`copy_object_internal`] to copy the object. /// either [compose_object](Client::compose_object) or [`copy_object_internal`](Client::copy_object_internal) to copy the object.
pub fn copy_object<S1: Into<String>, S2: Into<String>>( pub fn copy_object<S1: Into<String>, S2: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,
@ -60,8 +84,8 @@ impl Client {
ComposeObjectInternal::new(self.clone(), bucket.into(), object.into()) ComposeObjectInternal::new(self.clone(), bucket.into(), object.into())
} }
/// compose object is high-order API that calls [`compose_object_internal`] and if that call fails, /// compose object is high-order API that calls [`compose_object_internal`](Client::compose_object_internal) and if that call fails,
/// it calls ['abort_multipart_upload`]. /// it calls ['abort_multipart_upload`](Client::abort_multipart_upload).
pub fn compose_object<S1: Into<String>, S2: Into<String>>( pub fn compose_object<S1: Into<String>, S2: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,

View File

@ -16,31 +16,31 @@
//! S3 APIs for bucket objects. //! S3 APIs for bucket objects.
use super::Client; use super::Client;
use crate::s3::builders::MakeBucket; use crate::s3::builders::CreateBucket;
impl Client { impl Client {
/// Creates a [`MakeBucket`] request builder. /// Creates a [`CreateBucket`] request builder.
/// ///
/// To execute the request, call [`MakeBucket::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`CreateBucket::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`MakeBucketResponse`](crate::s3::response::MakeBucketResponse). /// which returns a [`Result`] containing a [`CreateBucketResponse`](crate::s3::response::CreateBucketResponse).
/// ///
/// # Example /// # Example
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::MakeBucketResponse; /// use minio::s3::response::CreateBucketResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: MakeBucketResponse = /// let resp: CreateBucketResponse = client
/// client.make_bucket("bucket-name").send().await.unwrap(); /// .create_bucket("bucket-name")
/// .send().await.unwrap();
/// println!("Made bucket '{}' in region '{}'", resp.bucket, resp.region); /// println!("Made bucket '{}' in region '{}'", resp.bucket, resp.region);
/// } /// }
/// ``` /// ```
pub fn make_bucket<S: Into<String>>(&self, bucket: S) -> MakeBucket { pub fn create_bucket<S: Into<String>>(&self, bucket: S) -> CreateBucket {
MakeBucket::new(self.clone(), bucket.into()) CreateBucket::new(self.clone(), bucket.into())
} }
} }

View File

@ -16,48 +16,46 @@
//! S3 APIs for bucket objects. //! S3 APIs for bucket objects.
use super::Client; use super::Client;
use crate::s3::builders::{ObjectToDelete, RemoveBucket, RemoveObject}; use crate::s3::builders::{DeleteBucket, ObjectToDelete, RemoveObject};
use crate::s3::error::{Error, ErrorCode}; use crate::s3::error::{Error, ErrorCode};
use crate::s3::response::DeleteResult; use crate::s3::response::DeleteResult;
use crate::s3::response::{ use crate::s3::response::{
DisableObjectLegalHoldResponse, RemoveBucketResponse, RemoveObjectResponse, DeleteBucketResponse, PutObjectLegalHoldResponse, RemoveObjectResponse, RemoveObjectsResponse,
RemoveObjectsResponse,
}; };
use crate::s3::types::{S3Api, ToStream}; use crate::s3::types::{S3Api, ToStream};
use futures::StreamExt; use futures::StreamExt;
impl Client { impl Client {
/// Creates a [`RemoveBucket`] request builder. /// Creates a [`DeleteBucket`] request builder.
/// ///
/// To execute the request, call [`RemoveBucket::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`DeleteBucket::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`RemoveBucketResponse`](crate::s3::response::RemoveBucketResponse). /// which returns a [`Result`] containing a [`DeleteBucketResponse`].
/// ///
/// # Example /// # Example
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::RemoveBucketResponse; /// use minio::s3::response::DeleteBucketResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: RemoveBucketResponse = /// let resp: DeleteBucketResponse =
/// client.remove_bucket("bucket-name").send().await.unwrap(); /// client.delete_bucket("bucket-name").send().await.unwrap();
/// println!("bucket '{}' in region '{}' is removed", resp.bucket, resp.region); /// println!("bucket '{}' in region '{}' is removed", resp.bucket, resp.region);
/// } /// }
/// ``` /// ```
pub fn remove_bucket<S: Into<String>>(&self, bucket: S) -> RemoveBucket { pub fn delete_bucket<S: Into<String>>(&self, bucket: S) -> DeleteBucket {
RemoveBucket::new(self.clone(), bucket.into()) DeleteBucket::new(self.clone(), bucket.into())
} }
/// Removes a bucket and also removes non-empty buckets by first removing all objects before /// Deletes a bucket and also deletes non-empty buckets by first removing all objects before
/// deleting the bucket. Bypasses governance mode and legal hold. /// deleting the bucket. Bypasses governance mode and legal hold.
pub async fn remove_and_purge_bucket<S: Into<String>>( pub async fn delete_and_purge_bucket<S: Into<String>>(
&self, &self,
bucket: S, bucket: S,
) -> Result<RemoveBucketResponse, Error> { ) -> Result<DeleteBucketResponse, Error> {
let bucket: String = bucket.into(); let bucket: String = bucket.into();
if self.is_minio_express() { if self.is_minio_express() {
let mut stream = self.list_objects(&bucket).to_stream().await; let mut stream = self.list_objects(&bucket).to_stream().await;
@ -98,8 +96,8 @@ impl Client {
DeleteResult::Deleted(_) => {} DeleteResult::Deleted(_) => {}
DeleteResult::Error(v) => { DeleteResult::Error(v) => {
// the object is not deleted. try to disable legal hold and try again. // the object is not deleted. try to disable legal hold and try again.
let _resp: DisableObjectLegalHoldResponse = self let _resp: PutObjectLegalHoldResponse = self
.disable_object_legal_hold(&bucket, &v.object_name) .put_object_legal_hold(&bucket, &v.object_name, false)
.version_id(v.version_id.clone()) .version_id(v.version_id.clone())
.send() .send()
.await?; .await?;
@ -118,11 +116,11 @@ impl Client {
} }
} }
} }
match self.remove_bucket(bucket).send().await { match self.delete_bucket(bucket).send().await {
Ok(resp) => Ok(resp), Ok(resp) => Ok(resp),
Err(Error::S3Error(e)) => { Err(Error::S3Error(e)) => {
if e.code == ErrorCode::NoSuchBucket { if e.code == ErrorCode::NoSuchBucket {
Ok(RemoveBucketResponse { Ok(DeleteBucketResponse {
headers: e.headers, headers: e.headers,
bucket: e.bucket_name, bucket: e.bucket_name,
region: String::new(), region: String::new(),

View File

@ -31,12 +31,12 @@ impl Client {
/// use minio::s3::response::DeleteBucketEncryptionResponse; /// use minio::s3::response::DeleteBucketEncryptionResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteBucketEncryptionResponse = /// let resp: DeleteBucketEncryptionResponse = client
/// client.delete_bucket_encryption("bucket-name").send().await.unwrap(); /// .delete_bucket_encryption("bucket-name")
/// .send().await.unwrap();
/// println!("bucket '{}' is deleted", resp.bucket); /// println!("bucket '{}' is deleted", resp.bucket);
/// } /// }
/// ``` /// ```

View File

@ -31,12 +31,12 @@ impl Client {
/// use minio::s3::response::DeleteBucketLifecycleResponse; /// use minio::s3::response::DeleteBucketLifecycleResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteBucketLifecycleResponse = /// let resp: DeleteBucketLifecycleResponse = client
/// client.delete_bucket_lifecycle("bucket-name").send().await.unwrap(); /// .delete_bucket_lifecycle("bucket-name")
/// .send().await.unwrap();
/// println!("lifecycle of bucket '{}' is deleted", resp.bucket); /// println!("lifecycle of bucket '{}' is deleted", resp.bucket);
/// } /// }
/// ``` /// ```

View File

@ -31,12 +31,12 @@ impl Client {
/// use minio::s3::response::DeleteBucketNotificationResponse; /// use minio::s3::response::DeleteBucketNotificationResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteBucketNotificationResponse = /// let resp: DeleteBucketNotificationResponse = client
/// client.delete_bucket_notification("bucket-name").send().await.unwrap(); /// .delete_bucket_notification("bucket-name")
/// .send().await.unwrap();
/// println!("notification of bucket '{}' is deleted", resp.bucket); /// println!("notification of bucket '{}' is deleted", resp.bucket);
/// } /// }
/// ``` /// ```

View File

@ -19,7 +19,6 @@ use super::Client;
use crate::s3::builders::DeleteBucketPolicy; use crate::s3::builders::DeleteBucketPolicy;
impl Client { impl Client {
/// Create a DeleteBucketPolicy request builder.
/// Creates a [`DeleteBucketPolicy`] request builder. /// Creates a [`DeleteBucketPolicy`] request builder.
/// ///
/// To execute the request, call [`DeleteBucketPolicy::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`DeleteBucketPolicy::send()`](crate::s3::types::S3Api::send),
@ -32,12 +31,12 @@ impl Client {
/// use minio::s3::response::DeleteBucketPolicyResponse; /// use minio::s3::response::DeleteBucketPolicyResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteBucketPolicyResponse = /// let resp: DeleteBucketPolicyResponse = client
/// client.delete_bucket_policy("bucket-name").send().await.unwrap(); /// .delete_bucket_policy("bucket-name")
/// .send().await.unwrap();
/// println!("policy of bucket '{}' is deleted", resp.bucket); /// println!("policy of bucket '{}' is deleted", resp.bucket);
/// } /// }
/// ``` /// ```

View File

@ -33,12 +33,12 @@ impl Client {
/// use minio::s3::response::DeleteBucketReplicationResponse; /// use minio::s3::response::DeleteBucketReplicationResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteBucketReplicationResponse = /// let resp: DeleteBucketReplicationResponse = client
/// client.delete_bucket_replication("bucket-name").send().await.unwrap(); /// .delete_bucket_replication("bucket-name")
/// .send().await.unwrap();
/// println!("replication of bucket '{}' is deleted", resp.bucket); /// println!("replication of bucket '{}' is deleted", resp.bucket);
/// } /// }
/// ``` /// ```

View File

@ -16,13 +16,13 @@
//! S3 APIs for bucket objects. //! S3 APIs for bucket objects.
use super::Client; use super::Client;
use crate::s3::builders::DeleteBucketTags; use crate::s3::builders::DeleteBucketTagging;
impl Client { impl Client {
/// Creates a [`DeleteBucketTags`] request builder. /// Creates a [`DeleteBucketTagging`] request builder.
/// ///
/// To execute the request, call [`DeleteBucketTagsResponse::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`DeleteBucketTagging::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`DeleteBucketTagsResponse`](crate::s3::response::DeleteBucketTagsResponse). /// which returns a [`Result`] containing a [`DeleteBucketTagsResponse`](crate::s3::response::DeleteBucketTaggingResponse).
/// ///
/// 🛈 This operation is not supported for express buckets. /// 🛈 This operation is not supported for express buckets.
/// ///
@ -30,19 +30,19 @@ impl Client {
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::DeleteBucketTagsResponse; /// use minio::s3::response::DeleteBucketTaggingResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteBucketTagsResponse = /// let resp: DeleteBucketTaggingResponse = client
/// client.delete_bucket_tags("bucket-name").send().await.unwrap(); /// .delete_bucket_tagging("bucket-name")
/// .send().await.unwrap();
/// println!("tags of bucket '{}' are deleted", resp.bucket); /// println!("tags of bucket '{}' are deleted", resp.bucket);
/// } /// }
/// ``` /// ```
pub fn delete_bucket_tags<S: Into<String>>(&self, bucket: S) -> DeleteBucketTags { pub fn delete_bucket_tagging<S: Into<String>>(&self, bucket: S) -> DeleteBucketTagging {
DeleteBucketTags::new(self.clone(), bucket.into()) DeleteBucketTagging::new(self.clone(), bucket.into())
} }
} }

View File

@ -30,24 +30,23 @@ impl Client {
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::{DeleteObjectLockConfigResponse, MakeBucketResponse, SetObjectLockConfigResponse}; /// use minio::s3::response::{DeleteObjectLockConfigResponse, CreateBucketResponse, PutObjectLockConfigResponse};
/// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode}; /// use minio::s3::types::{S3Api, ObjectLockConfig, RetentionMode};
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let bucket_name = "bucket-name"; /// let bucket_name = "bucket-name";
/// ///
/// let resp: MakeBucketResponse = /// let resp: CreateBucketResponse =
/// client.make_bucket(bucket_name).object_lock(true).send().await.unwrap(); /// client.create_bucket(bucket_name).object_lock(true).send().await.unwrap();
/// println!("created bucket '{}' with object locking enabled", resp.bucket); /// println!("created bucket '{}' with object locking enabled", resp.bucket);
/// ///
/// const DURATION_DAYS: i32 = 7; /// const DURATION_DAYS: i32 = 7;
/// let config = ObjectLockConfig::new(RetentionMode::GOVERNANCE, Some(DURATION_DAYS), None).unwrap(); /// let config = ObjectLockConfig::new(RetentionMode::GOVERNANCE, Some(DURATION_DAYS), None).unwrap();
/// ///
/// let resp: SetObjectLockConfigResponse = /// let resp: PutObjectLockConfigResponse =
/// client.set_object_lock_config(bucket_name).config(config).send().await.unwrap(); /// client.put_object_lock_config(bucket_name).config(config).send().await.unwrap();
/// println!("configured object locking for bucket '{}'", resp.bucket); /// println!("configured object locking for bucket '{}'", resp.bucket);
/// ///
/// let resp: DeleteObjectLockConfigResponse = /// let resp: DeleteObjectLockConfigResponse =

View File

@ -16,13 +16,13 @@
//! S3 APIs for bucket objects. //! S3 APIs for bucket objects.
use super::Client; use super::Client;
use crate::s3::builders::DeleteObjectTags; use crate::s3::builders::DeleteObjectTagging;
impl Client { impl Client {
/// Creates a [`DeleteObjectTags`] request builder. /// Creates a [`DeleteObjectTagging`] request builder.
/// ///
/// To execute the request, call [`DeleteObjectTags::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`DeleteObjectTagging::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`DeleteObjectTagsResponse`](crate::s3::response::DeleteObjectTagsResponse). /// which returns a [`Result`] containing a [`DeleteObjectTagsResponse`](crate::s3::response::DeleteObjectTaggingResponse).
/// ///
/// 🛈 This operation is not supported for express buckets. /// 🛈 This operation is not supported for express buckets.
/// ///
@ -30,23 +30,23 @@ impl Client {
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::DeleteObjectTagsResponse; /// use minio::s3::response::DeleteObjectTaggingResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: DeleteObjectTagsResponse = /// let resp: DeleteObjectTaggingResponse = client
/// client.delete_object_tags("bucket-name", "object_name").send().await.unwrap(); /// .delete_object_tagging("bucket-name", "object_name")
/// .send().await.unwrap();
/// println!("legal hold of object '{}' in bucket '{}' is deleted", resp.object, resp.bucket); /// println!("legal hold of object '{}' in bucket '{}' is deleted", resp.object, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn delete_object_tags<S1: Into<String>, S2: Into<String>>( pub fn delete_object_tagging<S1: Into<String>, S2: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,
object: S2, object: S2,
) -> DeleteObjectTags { ) -> DeleteObjectTagging {
DeleteObjectTags::new(self.clone(), bucket.into(), object.into()) DeleteObjectTagging::new(self.clone(), bucket.into(), object.into())
} }
} }

View File

@ -35,7 +35,6 @@ impl Client {
/// use minio::s3::builders::ObjectToDelete; /// use minio::s3::builders::ObjectToDelete;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here

View File

@ -31,13 +31,13 @@ impl Client {
/// use minio::s3::response::GetBucketEncryptionResponse; /// use minio::s3::response::GetBucketEncryptionResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketEncryptionResponse = /// let resp: GetBucketEncryptionResponse = client
/// client.get_bucket_encryption("bucket-name").send().await.unwrap(); /// .get_bucket_encryption("bucket-name")
/// println!("retrieved SseConfig '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved SseConfig '{:?}' from bucket '{}'", resp.config, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_encryption<S: Into<String>>(&self, bucket: S) -> GetBucketEncryption { pub fn get_bucket_encryption<S: Into<String>>(&self, bucket: S) -> GetBucketEncryption {

View File

@ -33,13 +33,13 @@ impl Client {
/// use minio::s3::response::GetBucketLifecycleResponse; /// use minio::s3::response::GetBucketLifecycleResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketLifecycleResponse = /// let resp: GetBucketLifecycleResponse = client
/// client.get_bucket_lifecycle("bucket-name").send().await.unwrap(); /// .get_bucket_lifecycle("bucket-name")
/// println!("retrieved bucket lifecycle config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved bucket lifecycle config '{:?}' from bucket '{}'", resp.config, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> GetBucketLifecycle { pub fn get_bucket_lifecycle<S: Into<String>>(&self, bucket: S) -> GetBucketLifecycle {

View File

@ -31,13 +31,13 @@ impl Client {
/// use minio::s3::response::GetBucketNotificationResponse; /// use minio::s3::response::GetBucketNotificationResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketNotificationResponse = /// let resp: GetBucketNotificationResponse = client
/// client.get_bucket_notification("bucket-name").send().await.unwrap(); /// .get_bucket_notification("bucket-name")
/// println!("retrieved bucket notification config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved bucket notification config '{:?}' from bucket '{}'", resp.config, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_notification<S: Into<String>>(&self, bucket: S) -> GetBucketNotification { pub fn get_bucket_notification<S: Into<String>>(&self, bucket: S) -> GetBucketNotification {

View File

@ -31,13 +31,13 @@ impl Client {
/// use minio::s3::response::GetBucketPolicyResponse; /// use minio::s3::response::GetBucketPolicyResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketPolicyResponse = /// let resp: GetBucketPolicyResponse = client
/// client.get_bucket_policy("bucket-name").send().await.unwrap(); /// .get_bucket_policy("bucket-name")
/// println!("retrieved bucket policy config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved bucket policy config '{:?}' from bucket '{}'", resp.config, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_policy<S: Into<String>>(&self, bucket: S) -> GetBucketPolicy { pub fn get_bucket_policy<S: Into<String>>(&self, bucket: S) -> GetBucketPolicy {

View File

@ -33,13 +33,13 @@ impl Client {
/// use minio::s3::response::GetBucketReplicationResponse; /// use minio::s3::response::GetBucketReplicationResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketReplicationResponse = /// let resp: GetBucketReplicationResponse = client
/// client.get_bucket_replication("bucket-name").send().await.unwrap(); /// .get_bucket_replication("bucket-name")
/// println!("retrieved bucket replication config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved bucket replication config '{:?}' from bucket '{}'", resp.config, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_replication<S: Into<String>>(&self, bucket: S) -> GetBucketReplication { pub fn get_bucket_replication<S: Into<String>>(&self, bucket: S) -> GetBucketReplication {

View File

@ -16,13 +16,13 @@
//! S3 APIs for bucket objects. //! S3 APIs for bucket objects.
use super::Client; use super::Client;
use crate::s3::builders::GetBucketTags; use crate::s3::builders::GetBucketTagging;
impl Client { impl Client {
/// Creates a [`GetBucketTags`] request builder. /// Creates a [`GetBucketTagging`] request builder.
/// ///
/// To execute the request, call [`GetBucketTags::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`GetBucketTags::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`GetBucketTagsResponse`](crate::s3::response::GetBucketTagsResponse). /// which returns a [`Result`] containing a [`GetBucketTagsResponse`](crate::s3::response::GetBucketTaggingResponse).
/// ///
/// 🛈 This operation is not supported for express buckets. /// 🛈 This operation is not supported for express buckets.
/// ///
@ -30,19 +30,19 @@ impl Client {
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::GetBucketTagsResponse; /// use minio::s3::response::GetBucketTaggingResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketTagsResponse = /// let resp: GetBucketTaggingResponse = client
/// client.get_bucket_tags("bucket-name").send().await.unwrap(); /// .get_bucket_tagging("bucket-name")
/// println!("retrieved bucket tags '{:?}' from bucket '{}' is enabled", resp.tags, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved bucket tags '{:?}' from bucket '{}'", resp.tags, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_tags<S: Into<String>>(&self, bucket: S) -> GetBucketTags { pub fn get_bucket_tagging<S: Into<String>>(&self, bucket: S) -> GetBucketTagging {
GetBucketTags::new(self.clone(), bucket.into()) GetBucketTagging::new(self.clone(), bucket.into())
} }
} }

View File

@ -33,13 +33,13 @@ impl Client {
/// use minio::s3::response::GetBucketVersioningResponse; /// use minio::s3::response::GetBucketVersioningResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetBucketVersioningResponse = /// let resp: GetBucketVersioningResponse = client
/// client.get_bucket_versioning("bucket-name").send().await.unwrap(); /// .get_bucket_versioning("bucket-name")
/// println!("retrieved versioning status '{:?}' from bucket '{}' is enabled", resp.status, resp.bucket); /// .send().await.unwrap();
/// println!("retrieved versioning status '{:?}' from bucket '{}'", resp.status, resp.bucket);
/// } /// }
/// ``` /// ```
pub fn get_bucket_versioning<S: Into<String>>(&self, bucket: S) -> GetBucketVersioning { pub fn get_bucket_versioning<S: Into<String>>(&self, bucket: S) -> GetBucketVersioning {

View File

@ -31,12 +31,12 @@ impl Client {
/// use minio::s3::response::GetObjectResponse; /// use minio::s3::response::GetObjectResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetObjectResponse = /// let resp: GetObjectResponse = client
/// client.get_object("bucket-name", "object-name").send().await.unwrap(); /// .get_object("bucket-name", "object-name")
/// .send().await.unwrap();
/// let content_bytes = resp.content.to_segmented_bytes().await.unwrap().to_bytes(); /// let content_bytes = resp.content.to_segmented_bytes().await.unwrap().to_bytes();
/// let content_str = String::from_utf8(content_bytes.to_vec()).unwrap(); /// let content_str = String::from_utf8(content_bytes.to_vec()).unwrap();
/// println!("retrieved content '{}'", content_str); /// println!("retrieved content '{}'", content_str);

View File

@ -16,13 +16,13 @@
//! S3 APIs for bucket objects. //! S3 APIs for bucket objects.
use super::Client; use super::Client;
use crate::s3::builders::EnableObjectLegalHold; use crate::s3::builders::GetObjectLegalHold;
impl Client { impl Client {
/// Creates a [`EnableObjectLegalHold`] request builder. /// Creates a [`GetObjectLegalHold`] request builder.
/// ///
/// To execute the request, call [`EnableObjectLegalHold::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`GetObjectLegalHold::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`EnableObjectLegalHoldResponse`](crate::s3::response::EnableObjectLegalHoldResponse). /// which returns a [`Result`] containing a [`GetObjectLegalHoldResponse`](crate::s3::response::GetObjectLegalHoldResponse).
/// ///
/// 🛈 This operation is not supported for express buckets. /// 🛈 This operation is not supported for express buckets.
/// ///
@ -30,23 +30,23 @@ impl Client {
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::EnableObjectLegalHoldResponse; /// use minio::s3::response::GetObjectLegalHoldResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: EnableObjectLegalHoldResponse = /// let resp: GetObjectLegalHoldResponse = client
/// client.enable_object_legal_hold("bucket-name", "object-name").send().await.unwrap(); /// .get_object_legal_hold("bucket-name", "object-name")
/// println!("legal hold of object '{}' in bucket '{}' is enabled", resp.object, resp.bucket); /// .send().await.unwrap();
/// println!("legal hold of object '{}' in bucket '{}' is enabled: {}", resp.object, resp.bucket, resp.enabled);
/// } /// }
/// ``` /// ```
pub fn enable_object_legal_hold<S1: Into<String>, S2: Into<String>>( pub fn get_object_legal_hold<S1: Into<String>, S2: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,
object: S2, object: S2,
) -> EnableObjectLegalHold { ) -> GetObjectLegalHold {
EnableObjectLegalHold::new(self.clone(), bucket.into(), object.into()) GetObjectLegalHold::new(self.clone(), bucket.into(), object.into())
} }
} }

View File

@ -33,12 +33,12 @@ impl Client {
/// use minio::s3::response::GetObjectLockConfigResponse; /// use minio::s3::response::GetObjectLockConfigResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetObjectLockConfigResponse = /// let resp: GetObjectLockConfigResponse = client
/// client.get_object_lock_config("bucket-name").send().await.unwrap(); /// .get_object_lock_config("bucket-name")
/// .send().await.unwrap();
/// println!("retrieved object lock config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket); /// println!("retrieved object lock config '{:?}' from bucket '{}' is enabled", resp.config, resp.bucket);
/// } /// }
/// ``` /// ```

View File

@ -15,39 +15,38 @@
//! S3 APIs for downloading objects. //! S3 APIs for downloading objects.
use crate::s3::builders::ObjectPrompt; use crate::s3::builders::GetObjectPrompt;
use super::Client; use super::Client;
impl Client { impl Client {
/// Creates a [`ObjectPrompt`] request builder. Prompt an object using natural language. /// Creates a [`GetObjectPrompt`] request builder. Prompt an object using natural language.
/// ///
/// To execute the request, call [`ObjectPrompt::send()`](crate::s3::types::S3Api::send), /// To execute the request, call [`GetObjectPrompt::send()`](crate::s3::types::S3Api::send),
/// which returns a [`Result`] containing a [`ObjectPromptResponse`](crate::s3::response::ObjectPromptResponse). /// which returns a [`Result`] containing a [`GetObjectPromptResponse`](crate::s3::response::GetObjectPromptResponse).
/// ///
/// # Example /// # Example
/// ///
/// ```no_run /// ```no_run
/// use minio::s3::Client; /// use minio::s3::Client;
/// use minio::s3::response::ObjectPromptResponse; /// use minio::s3::response::GetObjectPromptResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: ObjectPromptResponse = client /// let resp: GetObjectPromptResponse = client
/// .object_prompt("bucket-name", "object-name", "What is it about?") /// .get_object_prompt("bucket-name", "object-name", "What is it about?")
/// .send().await.unwrap(); /// .send().await.unwrap();
/// println!("the prompt response is: '{}'", resp.prompt_response); /// println!("the prompt response is: '{}'", resp.prompt_response);
/// } /// }
/// ``` /// ```
pub fn object_prompt<S1: Into<String>, S2: Into<String>, S3: Into<String>>( pub fn get_object_prompt<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
&self, &self,
bucket: S1, bucket: S1,
object: S2, object: S2,
prompt: S3, prompt: S3,
) -> ObjectPrompt { ) -> GetObjectPrompt {
ObjectPrompt::new(self.clone(), bucket.into(), object.into(), prompt.into()) GetObjectPrompt::new(self.clone(), bucket.into(), object.into(), prompt.into())
} }
} }

View File

@ -33,12 +33,12 @@ impl Client {
/// use minio::s3::response::GetObjectRetentionResponse; /// use minio::s3::response::GetObjectRetentionResponse;
/// use minio::s3::types::S3Api; /// use minio::s3::types::S3Api;
/// ///
///
/// #[tokio::main] /// #[tokio::main]
/// async fn main() { /// async fn main() {
/// let client: Client = Default::default(); // configure your client here /// let client: Client = Default::default(); // configure your client here
/// let resp: GetObjectRetentionResponse = /// let resp: GetObjectRetentionResponse = client
/// client.get_object_retention("bucket-name", "object-name").send().await.unwrap(); /// .get_object_retention("bucket-name", "object-name")
/// .send().await.unwrap();
/// println!("retrieved retention mode '{:?}' until '{:?}' from bucket '{}' is enabled", resp.retention_mode, resp.retain_until_date, resp.bucket); /// println!("retrieved retention mode '{:?}' until '{:?}' from bucket '{}' is enabled", resp.retention_mode, resp.retain_until_date, resp.bucket);
/// } /// }
/// ``` /// ```

Some files were not shown because too many files have changed in this diff Show More