s3_wire/operation/multipart/
part.rs1use std::{fmt, num::NonZeroU16};
2
3use super::{MultipartError, UploadId};
4use crate::operation::{Checksum, Conditions, CopySource, ObjectKey, RequestIds};
5use crate::stream::ByteStream;
6
7#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
9pub struct PartNumber(NonZeroU16);
10
11impl PartNumber {
12 pub const MAX: u16 = 10_000;
14
15 pub fn new(value: u16) -> Option<Self> {
17 NonZeroU16::new(value)
18 .filter(|value| value.get() <= Self::MAX)
19 .map(Self)
20 }
21
22 pub const fn get(self) -> u16 {
24 self.0.get()
25 }
26}
27
28pub struct UploadPartRequest {
30 key: ObjectKey,
31 upload_id: UploadId,
32 part_number: PartNumber,
33 body: ByteStream,
34 checksum: Checksum,
35}
36
37impl UploadPartRequest {
38 pub fn new(
40 key: ObjectKey,
41 upload_id: UploadId,
42 part_number: PartNumber,
43 body: ByteStream,
44 ) -> Self {
45 Self {
46 key,
47 upload_id,
48 part_number,
49 body,
50 checksum: Checksum::default(),
51 }
52 }
53
54 pub const fn key(&self) -> &ObjectKey {
56 &self.key
57 }
58
59 pub const fn upload_id(&self) -> &UploadId {
61 &self.upload_id
62 }
63
64 pub const fn part_number(&self) -> PartNumber {
66 self.part_number
67 }
68
69 pub const fn body(&self) -> &ByteStream {
71 &self.body
72 }
73
74 pub fn body_mut(&mut self) -> &mut ByteStream {
76 &mut self.body
77 }
78
79 pub const fn checksum(&self) -> &Checksum {
81 &self.checksum
82 }
83
84 pub fn with_checksum(mut self, checksum: Checksum) -> Self {
86 self.checksum = checksum;
87 self
88 }
89
90 pub fn into_body(self) -> ByteStream {
92 self.body
93 }
94}
95
96impl fmt::Debug for UploadPartRequest {
97 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
98 formatter
99 .debug_struct("UploadPartRequest")
100 .field("key", &self.key)
101 .field("upload_id", &self.upload_id)
102 .field("part_number", &self.part_number)
103 .field("body", &"<stream>")
104 .field("checksum", &self.checksum)
105 .finish()
106 }
107}
108
109#[derive(Clone, Debug, Eq, PartialEq)]
111pub struct UploadPartOutput {
112 pub part_number: PartNumber,
114 pub e_tag: String,
116 pub checksum: Checksum,
118 pub request_ids: RequestIds,
120}
121
122#[derive(Clone, Copy, Debug, Eq, PartialEq)]
124pub struct CopyPartRange {
125 start: u64,
126 end: u64,
127}
128
129impl CopyPartRange {
130 pub fn new(start: u64, end: u64) -> Result<Self, crate::operation::RangeError> {
132 if end < start {
133 return Err(crate::operation::RangeError { start, end });
134 }
135 Ok(Self { start, end })
136 }
137
138 pub const fn start(self) -> u64 {
140 self.start
141 }
142
143 pub const fn end(self) -> u64 {
145 self.end
146 }
147
148 pub(crate) fn header_value(self) -> String {
149 format!("bytes={}-{}", self.start, self.end)
150 }
151}
152
153#[derive(Clone, Debug, Eq, PartialEq)]
155pub struct UploadPartCopyRequest {
156 destination: ObjectKey,
157 upload_id: UploadId,
158 part_number: PartNumber,
159 pub source: CopySource,
161 pub source_range: Option<CopyPartRange>,
163 pub source_conditions: Conditions,
165}
166
167impl UploadPartCopyRequest {
168 pub fn new(
170 destination: ObjectKey,
171 upload_id: UploadId,
172 part_number: PartNumber,
173 source: CopySource,
174 ) -> Self {
175 Self {
176 destination,
177 upload_id,
178 part_number,
179 source,
180 source_range: None,
181 source_conditions: Conditions::default(),
182 }
183 }
184
185 pub const fn destination(&self) -> &ObjectKey {
187 &self.destination
188 }
189
190 pub const fn upload_id(&self) -> &UploadId {
192 &self.upload_id
193 }
194
195 pub const fn part_number(&self) -> PartNumber {
197 self.part_number
198 }
199}
200
201#[derive(Clone, Debug, Eq, PartialEq)]
203pub struct UploadPartCopyOutput {
204 pub part_number: PartNumber,
206 pub e_tag: String,
208 pub last_modified: Option<time::OffsetDateTime>,
210 pub checksum: Checksum,
212 pub request_ids: RequestIds,
214}
215
216impl UploadPartCopyOutput {
217 pub fn completed_part(&self) -> Result<CompletedPart, MultipartError> {
219 CompletedPart::new(self.part_number.get(), self.e_tag.clone())
220 .map(|part| part.with_checksum(self.checksum.clone()))
221 }
222}
223
224#[derive(Clone, Debug, Eq, PartialEq)]
226pub struct CompletedPart {
227 part_number: PartNumber,
228 e_tag: String,
229 checksum: Checksum,
230}
231
232impl CompletedPart {
233 pub fn new(part_number: u16, e_tag: impl Into<String>) -> Result<Self, MultipartError> {
235 let part_number =
236 PartNumber::new(part_number).ok_or(MultipartError::InvalidPartNumber(part_number))?;
237 let e_tag = e_tag.into();
238 if e_tag.trim().is_empty() {
239 return Err(MultipartError::EmptyETag {
240 part_number: part_number.get(),
241 });
242 }
243 Ok(Self {
244 part_number,
245 e_tag,
246 checksum: Checksum::default(),
247 })
248 }
249
250 pub const fn part_number(&self) -> PartNumber {
252 self.part_number
253 }
254
255 pub fn e_tag(&self) -> &str {
257 &self.e_tag
258 }
259
260 pub const fn checksum(&self) -> &Checksum {
262 &self.checksum
263 }
264
265 pub fn with_checksum(mut self, checksum: Checksum) -> Self {
267 self.checksum = checksum;
268 self
269 }
270}