aws_multipart_upload/types/
api.rs

1use aws_sdk_s3::types as s3;
2
3use crate::{
4    aws_ops::{create, upload},
5    AwsError,
6};
7
8/// The ID given to this upload by AWS.
9#[derive(Debug, Clone, PartialEq)]
10pub struct UploadId(String);
11
12impl From<String> for UploadId {
13    fn from(value: String) -> Self {
14        UploadId(value)
15    }
16}
17
18impl std::fmt::Display for UploadId {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        write!(f, "{}", self.0)
21    }
22}
23
24impl TryFrom<create::CreateMultipartUploadOutput> for UploadId {
25    type Error = AwsError;
26
27    fn try_from(value: create::CreateMultipartUploadOutput) -> Result<Self, Self::Error> {
28        let id = value.upload_id().ok_or(AwsError::Missing("upload_id"))?;
29        Ok(Self(id.to_string()))
30    }
31}
32
33/// The destination for the multipart upload in S3.
34#[derive(Debug, Clone, PartialEq)]
35pub struct UploadAddress {
36    bucket: String,
37    key: String,
38}
39
40impl UploadAddress {
41    pub fn new(bucket: String, key: String) -> Self {
42        Self { bucket, key }
43    }
44
45    pub fn bucket(&self) -> &str {
46        &self.bucket
47    }
48
49    pub fn key(&self) -> &str {
50        &self.key
51    }
52}
53
54/// The ID and destination, which appear in calls to AWS.
55#[derive(Debug, Clone, PartialEq)]
56pub struct UploadRequestParams {
57    upload_id: UploadId,
58    addr: UploadAddress,
59}
60
61impl UploadRequestParams {
62    pub fn new(upload_id: UploadId, addr: UploadAddress) -> Self {
63        Self { upload_id, addr }
64    }
65
66    pub fn upload_id(&self) -> &str {
67        &self.upload_id.0
68    }
69
70    pub fn bucket(&self) -> &str {
71        self.addr.bucket()
72    }
73
74    pub fn key(&self) -> &str {
75        self.addr.key()
76    }
77}
78
79/// An ID for a part that has been uploaded.
80#[derive(Debug, Clone, PartialEq)]
81pub struct EntityTag(String);
82
83impl EntityTag {
84    pub fn new(etag: String) -> Self {
85        Self(etag)
86    }
87}
88
89impl std::fmt::Display for EntityTag {
90    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
91        write!(f, "{}", self.0)
92    }
93}
94
95impl From<String> for EntityTag {
96    fn from(value: String) -> Self {
97        EntityTag(value)
98    }
99}
100
101impl TryFrom<upload::UploadPartOutput> for EntityTag {
102    type Error = AwsError;
103
104    fn try_from(value: upload::UploadPartOutput) -> Result<Self, Self::Error> {
105        Ok(Self(value.e_tag.ok_or(AwsError::Missing("e_tag"))?))
106    }
107}
108
109/// A type holding the history of parts already uploaded, expressed as a vector
110/// of `(EntityTag, i32)`.  The second coordinate is a monotonically increasing
111/// sequence of integers for each uploaded part.
112#[derive(Clone, Debug, PartialEq, Default)]
113pub struct UploadedParts {
114    pub parts: Vec<(EntityTag, i32)>,
115}
116
117impl UploadedParts {
118    pub fn new() -> Self {
119        Self::default()
120    }
121
122    /// Add the ID of a new completed part, incrementing the integer index.
123    pub fn update(&mut self, etag: EntityTag) {
124        let part_number = self.parts.len() + 1;
125        self.parts.push((etag, part_number as i32));
126    }
127
128    /// Get the last completed part number, which is equal to the maximum over
129    /// the vector of the part numbers.
130    pub fn last_completed(&self) -> i32 {
131        self.parts
132            .iter()
133            .fold(0, |acc, (_, p)| if acc >= *p { acc } else { *p })
134    }
135
136    /// Get the next part number, i.e., the one being built currently for the
137    /// next upload call.
138    pub fn current(&self) -> i32 {
139        self.last_completed() + 1
140    }
141
142    /// Return the current number of uploaded parts for this upload.
143    pub fn num_parts(&self) -> usize {
144        self.parts.len()
145    }
146}
147
148impl<'a> From<&'a UploadedParts> for s3::CompletedMultipartUpload {
149    fn from(val: &'a UploadedParts) -> s3::CompletedMultipartUpload {
150        let parts = val.parts.iter().fold(Vec::new(), |mut acc, (t, n)| {
151            acc.push(
152                s3::CompletedPart::builder()
153                    .e_tag(t.to_string())
154                    .part_number(*n)
155                    .build(),
156            );
157
158            acc
159        });
160
161        s3::CompletedMultipartUpload::builder()
162            .set_parts(Some(parts))
163            .build()
164    }
165}
166
167impl Extend<(EntityTag, i32)> for UploadedParts {
168    fn extend<T: IntoIterator<Item = (EntityTag, i32)>>(&mut self, iter: T) {
169        self.parts.extend(iter)
170    }
171}