1#[derive(Deserialize, Debug)]
2pub struct InitiateMultipartUploadResponse {
3 #[serde(rename = "Bucket")]
4 _bucket: String,
5 #[serde(rename = "Key")]
6 pub key: String,
7 #[serde(rename = "UploadId")]
8 pub upload_id: String,
9}
10
11#[derive(Deserialize, Debug, Clone)]
13pub struct Owner {
14 #[serde(rename = "DisplayName")]
15 pub display_name: Option<String>,
17 #[serde(rename = "ID")]
18 pub id: String,
20}
21
22#[derive(Deserialize, Debug)]
50pub struct GetObjectAttributesOutput {
51 #[serde(rename = "ETag")]
52 pub etag: String,
53 #[serde(rename = "Checksum")]
54 pub checksum: Checksum,
55 #[serde(rename = "ObjectParts")]
56 pub object_parts: ObjectParts,
57 #[serde(rename = "StorageClass")]
58 pub storage_class: String,
59 #[serde(rename = "ObjectSize")]
60 pub object_size: u64,
61}
62
63#[derive(Deserialize, Debug)]
64pub struct Checksum {
65 #[serde(rename = "ChecksumCRC32")]
66 pub checksum_crc32: String,
67 #[serde(rename = "ChecksumCRC32C")]
68 pub checksum_crc32c: String,
69 #[serde(rename = "ChecksumSHA1")]
70 pub checksum_sha1: String,
71 #[serde(rename = "ChecksumSHA256")]
72 pub checksum_sha256: String,
73}
74
75#[derive(Deserialize, Debug)]
76pub struct ObjectParts {
77 #[serde(rename = "IsTruncated")]
78 pub is_truncated: bool,
79 #[serde(rename = "MaxParts")]
80 pub max_parts: i32,
81 #[serde(rename = "NextPartNumberMarker")]
82 pub next_part_number_marker: i32,
83 #[serde(rename = "PartNumberMarker")]
84 pub part_number_marker: i32,
85 #[serde(rename = "Part")]
86 pub part: Vec<AttributesPart>,
87 #[serde(rename = "PartsCount")]
88 pub parts_count: u64,
89}
90
91#[derive(Deserialize, Debug)]
92pub struct AttributesPart {
93 #[serde(rename = "ChecksumCRC32")]
94 pub checksum_crc32: String,
95 #[serde(rename = "ChecksumCRC32C")]
96 pub checksum_crc32c: String,
97 #[serde(rename = "ChecksumSHA1")]
98 pub checksum_sha1: String,
99 #[serde(rename = "ChecksumSHA256")]
100 pub checksum_sha256: String,
101 #[serde(rename = "PartNumber")]
102 pub part_number: i32,
103 #[serde(rename = "Size")]
104 pub size: u64,
105}
106
107#[derive(Deserialize, Debug, Clone)]
109pub struct Object {
110 #[serde(rename = "LastModified")]
111 pub last_modified: String,
113 #[serde(rename = "ETag")]
114 pub e_tag: Option<String>,
117 #[serde(rename = "StorageClass")]
118 pub storage_class: Option<String>,
120 #[serde(rename = "Key")]
121 pub key: String,
123 #[serde(rename = "Owner")]
124 pub owner: Option<Owner>,
126 #[serde(rename = "Size")]
127 pub size: u64,
129}
130
131#[derive(Deserialize, Debug, Clone)]
133pub struct MultipartUpload {
134 #[serde(rename = "Initiated")]
135 pub initiated: String,
137 #[serde(rename = "StorageClass")]
138 pub storage_class: String,
140 #[serde(rename = "Key")]
141 pub key: String,
143 #[serde(rename = "Owner")]
144 pub owner: Option<Owner>,
146 #[serde(rename = "UploadId")]
147 pub id: String,
149}
150
151use std::fmt::{self};
152
153impl fmt::Display for CompleteMultipartUploadData {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 let mut parts = String::new();
156 for part in self.parts.clone() {
157 parts.push_str(&part.to_string())
158 }
159 write!(
160 f,
161 "<CompleteMultipartUpload>{}</CompleteMultipartUpload>",
162 parts
163 )
164 }
165}
166
167impl CompleteMultipartUploadData {
168 pub fn len(&self) -> usize {
169 self.to_string().len()
170 }
171
172 pub fn is_empty(&self) -> bool {
173 self.to_string().len() == 0
174 }
175}
176
177#[derive(Debug, Clone)]
178pub struct CompleteMultipartUploadData {
179 pub parts: Vec<Part>,
180}
181
182#[derive(Debug, Clone, Serialize)]
183pub struct Part {
184 #[serde(rename = "PartNumber")]
185 pub part_number: u32,
186 #[serde(rename = "ETag")]
187 pub etag: String,
188}
189
190impl fmt::Display for Part {
191 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
192 write!(f, "<Part>").expect("Can't fail");
193 write!(f, "<PartNumber>{}</PartNumber>", self.part_number).expect("Can't fail");
194 write!(f, "<ETag>{}</ETag>", self.etag).expect("Can't fail");
195 write!(f, "</Part>")
196 }
197}
198
199#[derive(Deserialize, Debug, Clone)]
200pub struct BucketLocationResult {
201 #[serde(rename = "$value")]
202 pub region: String,
203}
204
205#[derive(Deserialize, Debug, Clone)]
209pub struct ListBucketResult {
210 #[serde(rename = "Name")]
211 pub name: String,
213 #[serde(rename = "Delimiter")]
214 pub delimiter: Option<String>,
216 #[serde(rename = "MaxKeys")]
217 pub max_keys: Option<i32>,
219 #[serde(rename = "Prefix")]
220 pub prefix: Option<String>,
222 #[serde(rename = "ContinuationToken")] #[serde(alias = "Marker")] pub continuation_token: Option<String>,
227 #[serde(rename = "EncodingType")]
228 pub encoding_type: Option<String>,
230 #[serde(
231 default,
232 rename = "IsTruncated",
233 deserialize_with = "super::deserializer::bool_deserializer"
234 )]
235 pub is_truncated: bool,
244 #[serde(rename = "NextContinuationToken", default)] #[serde(alias = "NextMarker")] pub next_continuation_token: Option<String>,
247 #[serde(rename = "Contents", default)]
248 pub contents: Vec<Object>,
250 #[serde(rename = "CommonPrefixes", default)]
251 pub common_prefixes: Option<Vec<CommonPrefix>>,
254}
255
256#[derive(Deserialize, Debug, Clone)]
258pub struct ListMultipartUploadsResult {
259 #[serde(rename = "Bucket")]
260 pub name: String,
262 #[serde(rename = "NextKeyMarker")]
263 pub next_marker: Option<String>,
266 #[serde(rename = "NextUploadIdMarker")]
267 pub next_upload_id_marker: Option<String>,
270 #[serde(rename = "Prefix")]
271 pub prefix: Option<String>,
274 #[serde(rename = "KeyMarker")]
275 pub marker: Option<String>,
277 #[serde(rename = "UploadIdMarker")]
278 pub upload_id_marker: Option<String>,
280 #[serde(rename = "EncodingType")]
281 pub encoding_type: Option<String>,
283 #[serde(
284 rename = "IsTruncated",
285 deserialize_with = "super::deserializer::bool_deserializer"
286 )]
287 pub is_truncated: bool,
291 #[serde(rename = "Upload", default)]
292 pub uploads: Vec<MultipartUpload>,
294 #[serde(rename = "CommonPrefixes", default)]
295 pub common_prefixes: Option<Vec<CommonPrefix>>,
298}
299
300#[derive(Deserialize, Debug, Clone)]
302pub struct CommonPrefix {
303 #[serde(rename = "Prefix")]
304 pub prefix: String,
306}
307
308#[derive(Deserialize, Debug, Default, Clone)]
310pub struct HeadObjectResult {
311 #[serde(rename = "AcceptRanges")]
312 pub accept_ranges: Option<String>,
314 #[serde(rename = "CacheControl")]
315 pub cache_control: Option<String>,
317 #[serde(rename = "ContentDisposition")]
318 pub content_disposition: Option<String>,
320 #[serde(rename = "ContentEncoding")]
321 pub content_encoding: Option<String>,
323 #[serde(rename = "ContentLanguage")]
324 pub content_language: Option<String>,
326 #[serde(rename = "ContentLength")]
327 pub content_length: Option<i64>,
329 #[serde(rename = "ContentType")]
330 pub content_type: Option<String>,
332 #[serde(rename = "DeleteMarker")]
333 pub delete_marker: Option<bool>,
335 #[serde(rename = "ETag")]
336 pub e_tag: Option<String>,
338 #[serde(rename = "Expiration")]
339 pub expiration: Option<String>,
342 #[serde(rename = "Expires")]
343 pub expires: Option<String>,
345 #[serde(rename = "LastModified")]
346 pub last_modified: Option<String>,
348 #[serde(rename = "Metadata", default)]
349 pub metadata: Option<::std::collections::HashMap<String, String>>,
351 #[serde(rename = "MissingMeta")]
352 pub missing_meta: Option<i64>,
355 #[serde(rename = "ObjectLockLegalHoldStatus")]
356 pub object_lock_legal_hold_status: Option<String>,
359 #[serde(rename = "ObjectLockMode")]
360 pub object_lock_mode: Option<String>,
362 #[serde(rename = "ObjectLockRetainUntilDate")]
363 pub object_lock_retain_until_date: Option<String>,
366 #[serde(rename = "PartsCount")]
367 pub parts_count: Option<i64>,
369 #[serde(rename = "ReplicationStatus")]
370 pub replication_status: Option<String>,
372 #[serde(rename = "RequestCharged")]
373 pub request_charged: Option<String>,
374 #[serde(rename = "Restore")]
375 pub restore: Option<String>,
378 #[serde(rename = "SseCustomerAlgorithm")]
379 pub sse_customer_algorithm: Option<String>,
381 #[serde(rename = "SseCustomerKeyMd5")]
382 pub sse_customer_key_md5: Option<String>,
384 #[serde(rename = "SsekmsKeyId")]
385 pub ssekms_key_id: Option<String>,
387 #[serde(rename = "ServerSideEncryption")]
388 pub server_side_encryption: Option<String>,
391 #[serde(rename = "StorageClass")]
392 pub storage_class: Option<String>,
394 #[serde(rename = "VersionId")]
395 pub version_id: Option<String>,
397 #[serde(rename = "WebsiteRedirectLocation")]
398 pub website_redirect_location: Option<String>,
400}
401
402#[derive(Deserialize, Debug)]
403pub struct AwsError {
404 #[serde(rename = "Code")]
405 pub code: String,
406 #[serde(rename = "Message")]
407 pub message: String,
408 #[serde(rename = "RequestId")]
409 pub request_id: String,
410}
411
412#[derive(Debug, Clone)]
414pub struct ObjectIdentifier {
415 pub key: String,
417 pub version_id: Option<String>,
419}
420
421impl ObjectIdentifier {
422 pub fn new(key: impl Into<String>) -> Self {
423 Self {
424 key: key.into(),
425 version_id: None,
426 }
427 }
428
429 pub fn with_version(key: impl Into<String>, version_id: impl Into<String>) -> Self {
430 Self {
431 key: key.into(),
432 version_id: Some(version_id.into()),
433 }
434 }
435}
436
437#[derive(Debug, Clone)]
439pub struct DeleteObjectsRequest {
440 pub objects: Vec<ObjectIdentifier>,
441 pub quiet: bool,
443}
444
445impl fmt::Display for DeleteObjectsRequest {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 write!(
448 f,
449 r#"<Delete xmlns="http://s3.amazonaws.com/doc/2006-03-01/">"#
450 )
451 .expect("Can't fail");
452 if self.quiet {
453 write!(f, "<Quiet>true</Quiet>").expect("Can't fail");
454 }
455 for obj in &self.objects {
456 let escaped_key = quick_xml::escape::escape(&obj.key);
457 write!(f, "<Object><Key>{}</Key>", escaped_key).expect("Can't fail");
458 if let Some(ref vid) = obj.version_id {
459 let escaped_vid = quick_xml::escape::escape(vid);
460 write!(f, "<VersionId>{}</VersionId>", escaped_vid).expect("Can't fail");
461 }
462 write!(f, "</Object>").expect("Can't fail");
463 }
464 write!(f, "</Delete>")
465 }
466}
467
468impl DeleteObjectsRequest {
469 pub fn len(&self) -> usize {
470 self.to_string().len()
471 }
472
473 pub fn is_empty(&self) -> bool {
474 self.objects.is_empty()
475 }
476}
477
478#[derive(Deserialize, Debug, Clone)]
480pub struct DeletedObject {
481 #[serde(rename = "Key")]
482 pub key: String,
483 #[serde(rename = "VersionId")]
484 pub version_id: Option<String>,
485 #[serde(rename = "DeleteMarker")]
486 pub delete_marker: Option<bool>,
487 #[serde(rename = "DeleteMarkerVersionId")]
488 pub delete_marker_version_id: Option<String>,
489}
490
491#[derive(Deserialize, Debug, Clone)]
493pub struct DeleteError {
494 #[serde(rename = "Key")]
495 pub key: String,
496 #[serde(rename = "Code")]
497 pub code: String,
498 #[serde(rename = "Message")]
499 pub message: String,
500 #[serde(rename = "VersionId")]
501 pub version_id: Option<String>,
502}
503
504#[derive(Deserialize, Debug, Clone)]
506pub struct DeleteObjectsResult {
507 #[serde(rename = "Deleted", default)]
508 pub deleted: Vec<DeletedObject>,
509 #[serde(rename = "Error", default)]
510 pub errors: Vec<DeleteError>,
511}
512
513#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
514#[serde(rename = "CORSConfiguration")]
515pub struct CorsConfiguration {
516 #[serde(rename = "CORSRule")]
517 rules: Vec<CorsRule>,
518}
519
520impl CorsConfiguration {
521 pub fn new(rules: Vec<CorsRule>) -> Self {
522 CorsConfiguration { rules }
523 }
524}
525
526impl fmt::Display for CorsConfiguration {
527 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
528 let cors = quick_xml::se::to_string(&self).map_err(|_| fmt::Error)?;
529 let preamble = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
530 let cors = format!("{}{}", preamble, cors);
531 let cors = cors.replace(
532 "<CORSConfiguration>",
533 "<CORSConfiguration xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\">",
534 );
535
536 write!(f, "{}", cors)
537 }
538}
539
540#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
541pub struct CorsRule {
542 #[serde(rename = "AllowedHeader")]
543 #[serde(skip_serializing_if = "Option::is_none")]
544 allowed_headers: Option<Vec<String>>,
545 #[serde(rename = "AllowedMethod")]
546 allowed_methods: Vec<String>,
547 #[serde(rename = "AllowedOrigin")]
548 allowed_origins: Vec<String>,
549 #[serde(rename = "ExposeHeader")]
550 #[serde(skip_serializing_if = "Option::is_none")]
551 expose_headers: Option<Vec<String>>,
552 #[serde(skip_serializing_if = "Option::is_none")]
553 #[serde(rename = "ID")]
554 id: Option<String>,
555 #[serde(rename = "MaxAgeSeconds")]
556 #[serde(skip_serializing_if = "Option::is_none")]
557 max_age_seconds: Option<u32>,
558}
559
560impl CorsRule {
561 pub fn new(
562 allowed_headers: Option<Vec<String>>,
563 allowed_methods: Vec<String>,
564 allowed_origins: Vec<String>,
565 expose_headers: Option<Vec<String>>,
566 id: Option<String>,
567 max_age_seconds: Option<u32>,
568 ) -> Self {
569 Self {
570 allowed_headers,
571 allowed_methods,
572 allowed_origins,
573 expose_headers,
574 id,
575 max_age_seconds,
576 }
577 }
578}
579
580#[derive(Serialize, Deserialize, Clone, Debug)]
581#[serde(rename = "LifecycleConfiguration")]
582pub struct BucketLifecycleConfiguration {
583 #[serde(rename = "Rule")]
584 pub rules: Vec<LifecycleRule>,
585}
586
587impl BucketLifecycleConfiguration {
588 pub fn new(rules: Vec<LifecycleRule>) -> Self {
589 BucketLifecycleConfiguration { rules }
590 }
591}
592
593#[derive(Serialize, Deserialize, Debug, Clone, Default)]
594pub struct LifecycleRule {
595 #[serde(
596 rename = "AbortIncompleteMultipartUpload",
597 skip_serializing_if = "Option::is_none"
598 )]
599 pub abort_incomplete_multipart_upload: Option<AbortIncompleteMultipartUpload>,
600
601 #[serde(rename = "Expiration", skip_serializing_if = "Option::is_none")]
602 pub expiration: Option<Expiration>,
603
604 #[serde(rename = "Filter", skip_serializing_if = "Option::is_none")]
605 pub filter: Option<LifecycleFilter>,
606
607 #[serde(rename = "ID", skip_serializing_if = "Option::is_none")]
608 pub id: Option<String>,
609
610 #[serde(
611 rename = "NoncurrentVersionExpiration",
612 skip_serializing_if = "Option::is_none"
613 )]
614 pub noncurrent_version_expiration: Option<NoncurrentVersionExpiration>,
615
616 #[serde(
617 rename = "NoncurrentVersionTransition",
618 skip_serializing_if = "Option::is_none"
619 )]
620 pub noncurrent_version_transition: Option<Vec<NoncurrentVersionTransition>>,
621
622 #[serde(rename = "Status")]
623 pub status: String,
625
626 #[serde(rename = "Transition", skip_serializing_if = "Option::is_none")]
627 pub transition: Option<Vec<Transition>>,
628}
629
630pub struct LifecycleRuleBuilder {
631 lifecycle_rule: LifecycleRule,
632}
633
634impl LifecycleRule {
635 pub fn builder(status: &str) -> LifecycleRuleBuilder {
636 LifecycleRuleBuilder::new(status)
637 }
638}
639
640impl LifecycleRuleBuilder {
641 pub fn new(status: &str) -> LifecycleRuleBuilder {
642 LifecycleRuleBuilder {
643 lifecycle_rule: LifecycleRule {
644 status: status.to_string(),
645 ..Default::default()
646 },
647 }
648 }
649
650 pub fn abort_incomplete_multipart_upload(
651 mut self,
652 abort_incomplete_multipart_upload: AbortIncompleteMultipartUpload,
653 ) -> LifecycleRuleBuilder {
654 self.lifecycle_rule.abort_incomplete_multipart_upload =
655 Some(abort_incomplete_multipart_upload);
656 self
657 }
658
659 pub fn expiration(mut self, expiration: Expiration) -> LifecycleRuleBuilder {
660 self.lifecycle_rule.expiration = Some(expiration);
661 self
662 }
663
664 pub fn filter(mut self, filter: LifecycleFilter) -> LifecycleRuleBuilder {
665 self.lifecycle_rule.filter = Some(filter);
666 self
667 }
668
669 pub fn id(mut self, id: &str) -> LifecycleRuleBuilder {
670 self.lifecycle_rule.id = Some(id.to_string());
671 self
672 }
673
674 pub fn noncurrent_version_expiration(
675 mut self,
676 noncurrent_version_expiration: NoncurrentVersionExpiration,
677 ) -> LifecycleRuleBuilder {
678 self.lifecycle_rule.noncurrent_version_expiration = Some(noncurrent_version_expiration);
679 self
680 }
681
682 pub fn noncurrent_version_transition(
683 mut self,
684 noncurrent_version_transition: Vec<NoncurrentVersionTransition>,
685 ) -> LifecycleRuleBuilder {
686 self.lifecycle_rule.noncurrent_version_transition = Some(noncurrent_version_transition);
687 self
688 }
689
690 pub fn transition(mut self, transition: Vec<Transition>) -> LifecycleRuleBuilder {
691 self.lifecycle_rule.transition = Some(transition);
692 self
693 }
694
695 pub fn build(self) -> LifecycleRule {
696 self.lifecycle_rule
697 }
698}
699#[derive(Serialize, Deserialize, Debug, Clone)]
700pub struct AbortIncompleteMultipartUpload {
701 #[serde(
702 rename = "DaysAfterInitiation",
703 skip_serializing_if = "Option::is_none"
704 )]
705 pub days_after_initiation: Option<i32>,
706}
707
708impl AbortIncompleteMultipartUpload {
709 pub fn new(days_after_initiation: Option<i32>) -> Self {
710 Self {
711 days_after_initiation,
712 }
713 }
714}
715
716#[derive(Serialize, Deserialize, Debug, Clone, Default)]
717pub struct Expiration {
718 #[serde(rename = "Date", skip_serializing_if = "Option::is_none")]
720 pub date: Option<String>,
721
722 #[serde(rename = "Days", skip_serializing_if = "Option::is_none")]
723 pub days: Option<u32>,
724
725 #[serde(
727 rename = "ExpiredObjectDeleteMarker",
728 skip_serializing_if = "Option::is_none"
729 )]
730 pub expired_object_delete_marker: Option<bool>,
731}
732
733impl Expiration {
734 pub fn new(
735 date: Option<String>,
736 days: Option<u32>,
737 expired_object_delete_marker: Option<bool>,
738 ) -> Self {
739 Self {
740 date,
741 days,
742 expired_object_delete_marker,
743 }
744 }
745}
746
747#[derive(Serialize, Deserialize, Debug, Clone, Default)]
748pub struct LifecycleFilter {
749 #[serde(rename = "And", skip_serializing_if = "Option::is_none")]
750 pub and: Option<And>,
751
752 #[serde(
753 rename = "ObjectSizeGreaterThan",
754 skip_serializing_if = "Option::is_none"
755 )]
756 pub object_size_greater_than: Option<i64>,
757
758 #[serde(rename = "ObjectSizeLessThan", skip_serializing_if = "Option::is_none")]
759 pub object_size_less_than: Option<i64>,
760
761 #[serde(rename = "Prefix", skip_serializing_if = "Option::is_none")]
762 pub prefix: Option<String>,
763
764 #[serde(rename = "Tag", skip_serializing_if = "Option::is_none")]
765 pub tag: Option<Tag>,
766}
767impl LifecycleFilter {
768 pub fn new(
769 and: Option<And>,
770 object_size_greater_than: Option<i64>,
771 object_size_less_than: Option<i64>,
772 prefix: Option<String>,
773 tag: Option<Tag>,
774 ) -> Self {
775 Self {
776 and,
777 object_size_greater_than,
778 object_size_less_than,
779 prefix,
780 tag,
781 }
782 }
783}
784
785#[derive(Serialize, Deserialize, Debug, Clone)]
786pub struct And {
787 #[serde(
788 rename = "ObjectSizeGreaterThan",
789 skip_serializing_if = "Option::is_none"
790 )]
791 pub object_size_greater_than: Option<i64>,
792
793 #[serde(rename = "ObjectSizeLessThan", skip_serializing_if = "Option::is_none")]
794 pub object_size_less_than: Option<i64>,
795
796 #[serde(rename = "Prefix", skip_serializing_if = "Option::is_none")]
797 pub prefix: Option<String>,
798
799 #[serde(rename = "Tag", skip_serializing_if = "Option::is_none")]
800 pub tags: Option<Vec<Tag>>,
801}
802
803impl And {
804 pub fn new(
805 object_size_greater_than: Option<i64>,
806 object_size_less_than: Option<i64>,
807 prefix: Option<String>,
808 tags: Option<Vec<Tag>>,
809 ) -> Self {
810 Self {
811 object_size_greater_than,
812 object_size_less_than,
813 prefix,
814 tags,
815 }
816 }
817}
818
819#[derive(Serialize, Deserialize, Debug, Clone)]
820pub struct Tag {
821 #[serde(rename = "Key")]
822 pub key: String,
823
824 #[serde(rename = "Value")]
825 pub value: String,
826}
827
828impl Tag {
829 pub fn new(key: &str, value: &str) -> Self {
830 Self {
831 key: key.to_string(),
832 value: value.to_string(),
833 }
834 }
835}
836
837#[derive(Serialize, Deserialize, Debug, Clone)]
838pub struct NoncurrentVersionExpiration {
839 #[serde(
840 rename = "NewerNoncurrentVersions",
841 skip_serializing_if = "Option::is_none"
842 )]
843 pub newer_noncurrent_versions: Option<i32>,
844
845 #[serde(rename = "NoncurrentDays", skip_serializing_if = "Option::is_none")]
846 pub noncurrent_days: Option<i32>,
847}
848
849impl NoncurrentVersionExpiration {
850 pub fn new(newer_noncurrent_versions: Option<i32>, noncurrent_days: Option<i32>) -> Self {
851 NoncurrentVersionExpiration {
852 newer_noncurrent_versions,
853 noncurrent_days,
854 }
855 }
856}
857
858#[derive(Serialize, Deserialize, Debug, Clone)]
859pub struct NoncurrentVersionTransition {
860 #[serde(
861 rename = "NewerNoncurrentVersions",
862 skip_serializing_if = "Option::is_none"
863 )]
864 pub newer_noncurrent_versions: Option<i32>,
865
866 #[serde(rename = "NoncurrentDays", skip_serializing_if = "Option::is_none")]
867 pub noncurrent_days: Option<i32>,
868
869 #[serde(rename = "StorageClass", skip_serializing_if = "Option::is_none")]
870 pub storage_class: Option<String>,
872}
873
874impl NoncurrentVersionTransition {
875 pub fn new(
876 newer_noncurrent_versions: Option<i32>,
877 noncurrent_days: Option<i32>,
878 storage_class: Option<String>,
879 ) -> Self {
880 NoncurrentVersionTransition {
881 newer_noncurrent_versions,
882 noncurrent_days,
883 storage_class,
884 }
885 }
886}
887
888#[derive(Serialize, Deserialize, Debug, Clone)]
889pub struct Transition {
890 #[serde(rename = "Date", skip_serializing_if = "Option::is_none")]
891 pub date: Option<String>,
892
893 #[serde(rename = "Days", skip_serializing_if = "Option::is_none")]
894 pub days: Option<u32>,
895 #[serde(rename = "StorageClass")]
897 pub storage_class: Option<String>,
898}
899
900impl Transition {
901 pub fn new(date: Option<String>, days: Option<u32>, storage_class: Option<String>) -> Self {
902 Transition {
903 date,
904 days,
905 storage_class,
906 }
907 }
908}
909
910#[cfg(test)]
911mod test {
912 use crate::serde_types::{
913 AbortIncompleteMultipartUpload, BucketLifecycleConfiguration, Expiration, LifecycleFilter,
914 LifecycleRule, NoncurrentVersionExpiration, NoncurrentVersionTransition, Transition,
915 };
916
917 use super::{
918 CorsConfiguration, CorsRule, DeleteObjectsRequest, DeleteObjectsResult, ObjectIdentifier,
919 };
920
921 #[test]
922 fn cors_config_serde() {
923 let rule = CorsRule {
924 allowed_headers: Some(vec!["Authorization".to_string(), "Header2".to_string()]),
925 allowed_methods: vec!["GET".to_string(), "DELETE".to_string()],
926 allowed_origins: vec!["*".to_string()],
927 expose_headers: None,
928 id: Some("lala".to_string()),
929 max_age_seconds: None,
930 };
931
932 let config = CorsConfiguration {
933 rules: vec![rule.clone(), rule],
934 };
935
936 let se = quick_xml::se::to_string(&config).unwrap();
937 assert_eq!(
938 se,
939 r#"<CORSConfiguration><CORSRule><AllowedHeader>Authorization</AllowedHeader><AllowedHeader>Header2</AllowedHeader><AllowedMethod>GET</AllowedMethod><AllowedMethod>DELETE</AllowedMethod><AllowedOrigin>*</AllowedOrigin><ID>lala</ID></CORSRule><CORSRule><AllowedHeader>Authorization</AllowedHeader><AllowedHeader>Header2</AllowedHeader><AllowedMethod>GET</AllowedMethod><AllowedMethod>DELETE</AllowedMethod><AllowedOrigin>*</AllowedOrigin><ID>lala</ID></CORSRule></CORSConfiguration>"#
940 )
941 }
942
943 #[test]
944 fn lifecycle_config_serde() {
945 let rule = LifecycleRule {
946 abort_incomplete_multipart_upload: Some(AbortIncompleteMultipartUpload {
947 days_after_initiation: Some(30),
948 }),
949 expiration: Some(Expiration {
950 date: Some("2024-06-017".to_string()),
951 days: Some(30),
952 expired_object_delete_marker: Some(true),
953 }),
954 filter: Some(LifecycleFilter {
955 and: None,
956 object_size_greater_than: Some(10),
957 object_size_less_than: Some(50),
958 prefix: None,
959 tag: None,
960 }),
961 id: Some("lala".to_string()),
962 noncurrent_version_expiration: Some(NoncurrentVersionExpiration {
963 newer_noncurrent_versions: Some(30),
964 noncurrent_days: Some(30),
965 }),
966 noncurrent_version_transition: Some(vec![NoncurrentVersionTransition {
967 newer_noncurrent_versions: Some(30),
968 noncurrent_days: Some(30),
969 storage_class: Some("GLACIER".to_string()),
970 }]),
971 status: "Enabled".to_string(),
972 transition: Some(vec![Transition {
973 date: Some("2024-06-017".to_string()),
974 days: Some(30),
975 storage_class: Some("GLACIER".to_string()),
976 }]),
977 };
978
979 let config = BucketLifecycleConfiguration { rules: vec![rule] };
980
981 let se = quick_xml::se::to_string(&config).unwrap();
982 assert_eq!(
983 se,
984 r#"<LifecycleConfiguration><Rule><AbortIncompleteMultipartUpload><DaysAfterInitiation>30</DaysAfterInitiation></AbortIncompleteMultipartUpload><Expiration><Date>2024-06-017</Date><Days>30</Days><ExpiredObjectDeleteMarker>true</ExpiredObjectDeleteMarker></Expiration><Filter><ObjectSizeGreaterThan>10</ObjectSizeGreaterThan><ObjectSizeLessThan>50</ObjectSizeLessThan></Filter><ID>lala</ID><NoncurrentVersionExpiration><NewerNoncurrentVersions>30</NewerNoncurrentVersions><NoncurrentDays>30</NoncurrentDays></NoncurrentVersionExpiration><NoncurrentVersionTransition><NewerNoncurrentVersions>30</NewerNoncurrentVersions><NoncurrentDays>30</NoncurrentDays><StorageClass>GLACIER</StorageClass></NoncurrentVersionTransition><Status>Enabled</Status><Transition><Date>2024-06-017</Date><Days>30</Days><StorageClass>GLACIER</StorageClass></Transition></Rule></LifecycleConfiguration>"#
985 )
986 }
987
988 #[test]
989 fn delete_objects_request_serialize() {
990 let request = DeleteObjectsRequest {
991 objects: vec![
992 ObjectIdentifier::new("file1.txt"),
993 ObjectIdentifier::new("file2.txt"),
994 ObjectIdentifier::with_version("file3.txt", "v1"),
995 ],
996 quiet: false,
997 };
998
999 let se = request.to_string();
1000 assert_eq!(
1001 se,
1002 r#"<Delete xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Object><Key>file1.txt</Key></Object><Object><Key>file2.txt</Key></Object><Object><Key>file3.txt</Key><VersionId>v1</VersionId></Object></Delete>"#
1003 )
1004 }
1005
1006 #[test]
1007 fn delete_objects_request_serialize_quiet() {
1008 let request = DeleteObjectsRequest {
1009 objects: vec![ObjectIdentifier::new("file1.txt")],
1010 quiet: true,
1011 };
1012
1013 let se = request.to_string();
1014 assert_eq!(
1015 se,
1016 r#"<Delete xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Quiet>true</Quiet><Object><Key>file1.txt</Key></Object></Delete>"#
1017 )
1018 }
1019
1020 #[test]
1021 fn delete_objects_request_xml_escaping() {
1022 let request = DeleteObjectsRequest {
1023 objects: vec![ObjectIdentifier::new("file&name<>.txt")],
1024 quiet: false,
1025 };
1026
1027 let se = request.to_string();
1028 assert_eq!(
1029 se,
1030 r#"<Delete xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Object><Key>file&name<>.txt</Key></Object></Delete>"#
1031 )
1032 }
1033
1034 #[test]
1035 fn delete_objects_request_len() {
1036 let request = DeleteObjectsRequest {
1037 objects: vec![ObjectIdentifier::new("file1.txt")],
1038 quiet: false,
1039 };
1040
1041 assert_eq!(request.len(), request.to_string().len());
1042 assert!(!request.is_empty());
1043 }
1044
1045 #[test]
1046 fn delete_objects_result_deserialize() {
1047 let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
1048<DeleteResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
1049 <Deleted>
1050 <Key>file1.txt</Key>
1051 </Deleted>
1052 <Deleted>
1053 <Key>file2.txt</Key>
1054 <DeleteMarker>true</DeleteMarker>
1055 <DeleteMarkerVersionId>abc123</DeleteMarkerVersionId>
1056 </Deleted>
1057 <Error>
1058 <Key>file3.txt</Key>
1059 <Code>AccessDenied</Code>
1060 <Message>Access Denied</Message>
1061 </Error>
1062</DeleteResult>"#;
1063
1064 let result: DeleteObjectsResult = quick_xml::de::from_str(xml).unwrap();
1065 assert_eq!(result.deleted.len(), 2);
1066 assert_eq!(result.deleted[0].key, "file1.txt");
1067 assert_eq!(result.deleted[1].key, "file2.txt");
1068 assert_eq!(result.deleted[1].delete_marker, Some(true));
1069 assert_eq!(
1070 result.deleted[1].delete_marker_version_id,
1071 Some("abc123".to_string())
1072 );
1073 assert_eq!(result.errors.len(), 1);
1074 assert_eq!(result.errors[0].key, "file3.txt");
1075 assert_eq!(result.errors[0].code, "AccessDenied");
1076 assert_eq!(result.errors[0].message, "Access Denied");
1077 }
1078
1079 #[test]
1080 fn delete_objects_result_deserialize_empty() {
1081 let xml = r#"<?xml version="1.0" encoding="UTF-8"?>
1082<DeleteResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
1083</DeleteResult>"#;
1084
1085 let result: DeleteObjectsResult = quick_xml::de::from_str(xml).unwrap();
1086 assert_eq!(result.deleted.len(), 0);
1087 assert_eq!(result.errors.len(), 0);
1088 }
1089}