s3-wire 0.3.1

An async, streaming S3-compatible client for Rust
Documentation
use serde::{Deserialize, Serialize};

use super::common::root_is_error;
use crate::operation::{
    Checksum, CompleteMultipartUploadOutput, CompleteMultipartUploadRequest, ObjectKey,
};
use crate::protocol::xml::{expect_root, parse_bounded, serialize_bounded};
use crate::protocol::{ParsedS3Error, ProtocolError, parse_s3_error};

pub(crate) enum CompleteMultipartResponse {
    Complete(CompleteMultipartUploadOutput),
    EmbeddedError(ParsedS3Error),
}

#[derive(Serialize)]
#[serde(rename = "CompleteMultipartUpload")]
struct CompleteDocument<'a> {
    #[serde(rename = "Part")]
    parts: Vec<CompletedPartDocument<'a>>,
}

#[derive(Serialize)]
struct CompletedPartDocument<'a> {
    #[serde(rename = "PartNumber")]
    part_number: u16,
    #[serde(rename = "ETag")]
    e_tag: &'a str,
    #[serde(rename = "ChecksumCRC32", skip_serializing_if = "Option::is_none")]
    checksum_crc32: Option<&'a str>,
    #[serde(rename = "ChecksumCRC32C", skip_serializing_if = "Option::is_none")]
    checksum_crc32c: Option<&'a str>,
    #[serde(rename = "ChecksumCRC64NVME", skip_serializing_if = "Option::is_none")]
    checksum_crc64_nvme: Option<&'a str>,
    #[serde(rename = "ChecksumSHA1", skip_serializing_if = "Option::is_none")]
    checksum_sha1: Option<&'a str>,
    #[serde(rename = "ChecksumSHA256", skip_serializing_if = "Option::is_none")]
    checksum_sha256: Option<&'a str>,
}

#[derive(Deserialize)]
#[serde(rename = "CompleteMultipartUploadResult")]
struct CompleteResultDocument {
    #[serde(rename = "Location")]
    location: Option<String>,
    #[serde(rename = "Bucket")]
    bucket: Option<String>,
    #[serde(rename = "Key")]
    key: Option<String>,
    #[serde(rename = "ETag")]
    e_tag: Option<String>,
    #[serde(rename = "ChecksumCRC32")]
    checksum_crc32: Option<String>,
    #[serde(rename = "ChecksumCRC32C")]
    checksum_crc32c: Option<String>,
    #[serde(rename = "ChecksumCRC64NVME")]
    checksum_crc64_nvme: Option<String>,
    #[serde(rename = "ChecksumSHA1")]
    checksum_sha1: Option<String>,
    #[serde(rename = "ChecksumSHA256")]
    checksum_sha256: Option<String>,
}

pub(crate) fn serialize_complete_multipart_upload(
    request: &CompleteMultipartUploadRequest,
    maximum: usize,
) -> Result<Vec<u8>, ProtocolError> {
    let document = CompleteDocument {
        parts: request
            .completed_parts()
            .iter()
            .map(|part| CompletedPartDocument {
                part_number: part.part_number().get(),
                e_tag: part.e_tag(),
                checksum_crc32: part.checksum().crc32.as_deref(),
                checksum_crc32c: part.checksum().crc32c.as_deref(),
                checksum_crc64_nvme: part.checksum().crc64_nvme.as_deref(),
                checksum_sha1: part.checksum().sha1.as_deref(),
                checksum_sha256: part.checksum().sha256.as_deref(),
            })
            .collect(),
    };
    serialize_bounded(&document, maximum)
}

pub(crate) fn parse_complete_multipart_upload(
    body: &[u8],
    maximum: usize,
) -> Result<CompleteMultipartResponse, ProtocolError> {
    if root_is_error(body, maximum)? {
        return parse_s3_error(body, maximum).map(CompleteMultipartResponse::EmbeddedError);
    }
    expect_root(body, maximum, &[b"CompleteMultipartUploadResult"])?;
    let document: CompleteResultDocument = parse_bounded(body, maximum)?;
    let key = document
        .key
        .map(ObjectKey::new)
        .transpose()
        .map_err(|error| ProtocolError::InvalidField {
            field: "Key",
            reason: error.to_string(),
        })?;
    Ok(CompleteMultipartResponse::Complete(
        CompleteMultipartUploadOutput {
            location: document.location,
            bucket: document.bucket,
            key,
            e_tag: document.e_tag,
            version_id: None,
            checksum: Checksum {
                crc32: document.checksum_crc32,
                crc32c: document.checksum_crc32c,
                crc64_nvme: document.checksum_crc64_nvme,
                sha1: document.checksum_sha1,
                sha256: document.checksum_sha256,
            },
            request_ids: Default::default(),
        },
    ))
}