use super::{CompletedPart, PartNumber, UploadId};
use crate::operation::{Checksum, ObjectKey, RequestIds};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CompleteMultipartUploadRequest {
pub key: ObjectKey,
upload_id: UploadId,
completed_parts: Vec<CompletedPart>,
}
impl CompleteMultipartUploadRequest {
pub fn new(
key: ObjectKey,
upload_id: UploadId,
completed_parts: Vec<CompletedPart>,
) -> Result<Self, MultipartError> {
validate_completed_parts(&completed_parts)?;
Ok(Self {
key,
upload_id,
completed_parts,
})
}
pub fn completed_parts(&self) -> &[CompletedPart] {
&self.completed_parts
}
pub const fn upload_id(&self) -> &UploadId {
&self.upload_id
}
}
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct CompleteMultipartUploadOutput {
pub location: Option<String>,
pub bucket: Option<String>,
pub key: Option<ObjectKey>,
pub e_tag: Option<String>,
pub version_id: Option<String>,
pub checksum: Checksum,
pub request_ids: RequestIds,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct AbortMultipartUploadRequest {
key: ObjectKey,
upload_id: UploadId,
}
impl AbortMultipartUploadRequest {
pub fn new(key: ObjectKey, upload_id: UploadId) -> Self {
Self { key, upload_id }
}
pub const fn key(&self) -> &ObjectKey {
&self.key
}
pub const fn upload_id(&self) -> &UploadId {
&self.upload_id
}
}
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
pub enum MultipartError {
#[error("multipart part number {0} is outside 1..=10000")]
InvalidPartNumber(u16),
#[error("multipart part {part_number} has an empty ETag")]
EmptyETag {
part_number: u16,
},
#[error("multipart part {0:?} was recorded more than once")]
DuplicatePart(PartNumber),
#[error("a multipart upload cannot be completed without parts")]
NoCompletedParts,
#[error("multipart part {next:?} does not follow {previous:?} in ascending order")]
OutOfOrder {
previous: PartNumber,
next: PartNumber,
},
}
fn validate_completed_parts(parts: &[CompletedPart]) -> Result<(), MultipartError> {
if parts.is_empty() {
return Err(MultipartError::NoCompletedParts);
}
for window in parts.windows(2) {
if window[1].part_number() <= window[0].part_number() {
return Err(MultipartError::OutOfOrder {
previous: window[0].part_number(),
next: window[1].part_number(),
});
}
}
Ok(())
}