s3-wire 0.2.0

An async, streaming S3-compatible client for Rust
Documentation
use serde::Deserialize;
use time::{OffsetDateTime, format_description::well_known::Rfc3339};

use super::common::parse_upload_id;
use crate::operation::{ListMultipartUploadsOutput, MultipartUploadEntry, ObjectKey};
use crate::protocol::ProtocolError;
use crate::protocol::xml::{expect_root, parse_bounded};

#[derive(Deserialize)]
#[serde(rename = "ListMultipartUploadsResult")]
struct ListUploadsDocument {
    #[serde(rename = "Upload", default)]
    uploads: Vec<UploadDocument>,
    #[serde(rename = "CommonPrefixes", default)]
    common_prefixes: Vec<CommonPrefixDocument>,
    #[serde(rename = "IsTruncated", default)]
    is_truncated: bool,
    #[serde(rename = "NextKeyMarker")]
    next_key_marker: Option<String>,
    #[serde(rename = "NextUploadIdMarker")]
    next_upload_id_marker: Option<String>,
}

#[derive(Deserialize)]
struct UploadDocument {
    #[serde(rename = "Key")]
    key: String,
    #[serde(rename = "UploadId")]
    upload_id: String,
    #[serde(rename = "Initiated")]
    initiated: Option<String>,
    #[serde(rename = "StorageClass")]
    storage_class: Option<String>,
}

#[derive(Deserialize)]
struct CommonPrefixDocument {
    #[serde(rename = "Prefix")]
    prefix: String,
}

pub(crate) fn parse_list_multipart_uploads(
    body: &[u8],
    maximum: usize,
) -> Result<ListMultipartUploadsOutput, ProtocolError> {
    expect_root(body, maximum, &[b"ListMultipartUploadsResult"])?;
    let document: ListUploadsDocument = parse_bounded(body, maximum)?;
    let mut uploads = Vec::with_capacity(document.uploads.len());
    for upload in document.uploads {
        let upload_id = parse_upload_id(upload.upload_id, "Upload.UploadId")?;
        let initiated = upload
            .initiated
            .map(|value| {
                OffsetDateTime::parse(&value, &Rfc3339).map_err(|error| {
                    ProtocolError::InvalidField {
                        field: "Upload.Initiated",
                        reason: error.to_string(),
                    }
                })
            })
            .transpose()?;
        let key = ObjectKey::new(upload.key).map_err(|error| ProtocolError::InvalidField {
            field: "Upload.Key",
            reason: error.to_string(),
        })?;
        uploads.push(MultipartUploadEntry::new(
            key,
            upload_id,
            initiated,
            upload.storage_class,
        ));
    }
    let next_key_marker = document.next_key_marker.filter(|value| !value.is_empty());
    let next_upload_id_marker = document
        .next_upload_id_marker
        .filter(|value| !value.is_empty())
        .map(|value| parse_upload_id(value, "NextUploadIdMarker"))
        .transpose()?;
    Ok(ListMultipartUploadsOutput {
        uploads,
        common_prefixes: document
            .common_prefixes
            .into_iter()
            .map(|prefix| prefix.prefix)
            .collect(),
        is_truncated: document.is_truncated,
        next_key_marker,
        next_upload_id_marker,
        request_ids: Default::default(),
    })
}