s3_wire/operation/multipart/
completion.rs1use super::{CompletedPart, PartNumber, UploadId};
2use crate::operation::{Checksum, ObjectKey, RequestIds};
3
4#[derive(Clone, Debug, Eq, PartialEq)]
6pub struct CompleteMultipartUploadRequest {
7 pub key: ObjectKey,
9 upload_id: UploadId,
10 completed_parts: Vec<CompletedPart>,
11}
12
13impl CompleteMultipartUploadRequest {
14 pub fn new(
17 key: ObjectKey,
18 upload_id: UploadId,
19 completed_parts: Vec<CompletedPart>,
20 ) -> Result<Self, MultipartError> {
21 validate_completed_parts(&completed_parts)?;
22 Ok(Self {
23 key,
24 upload_id,
25 completed_parts,
26 })
27 }
28
29 pub fn completed_parts(&self) -> &[CompletedPart] {
31 &self.completed_parts
32 }
33
34 pub const fn upload_id(&self) -> &UploadId {
36 &self.upload_id
37 }
38}
39
40#[derive(Clone, Debug, Default, Eq, PartialEq)]
42pub struct CompleteMultipartUploadOutput {
43 pub location: Option<String>,
45 pub bucket: Option<String>,
47 pub key: Option<ObjectKey>,
49 pub e_tag: Option<String>,
51 pub version_id: Option<String>,
53 pub checksum: Checksum,
55 pub request_ids: RequestIds,
57}
58
59#[derive(Clone, Debug, Eq, PartialEq)]
61pub struct AbortMultipartUploadRequest {
62 key: ObjectKey,
63 upload_id: UploadId,
64}
65
66impl AbortMultipartUploadRequest {
67 pub fn new(key: ObjectKey, upload_id: UploadId) -> Self {
69 Self { key, upload_id }
70 }
71
72 pub const fn key(&self) -> &ObjectKey {
74 &self.key
75 }
76
77 pub const fn upload_id(&self) -> &UploadId {
79 &self.upload_id
80 }
81}
82
83#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
85pub enum MultipartError {
86 #[error("multipart part number {0} is outside 1..=10000")]
88 InvalidPartNumber(u16),
89 #[error("multipart part {part_number} has an empty ETag")]
91 EmptyETag {
92 part_number: u16,
94 },
95 #[error("multipart part {0:?} was recorded more than once")]
97 DuplicatePart(PartNumber),
98 #[error("a multipart upload cannot be completed without parts")]
100 NoCompletedParts,
101 #[error("multipart part {next:?} does not follow {previous:?} in ascending order")]
103 OutOfOrder {
104 previous: PartNumber,
106 next: PartNumber,
108 },
109}
110
111fn validate_completed_parts(parts: &[CompletedPart]) -> Result<(), MultipartError> {
112 if parts.is_empty() {
113 return Err(MultipartError::NoCompletedParts);
114 }
115 for window in parts.windows(2) {
116 if window[1].part_number() <= window[0].part_number() {
117 return Err(MultipartError::OutOfOrder {
118 previous: window[0].part_number(),
119 next: window[1].part_number(),
120 });
121 }
122 }
123 Ok(())
124}