1use crate::client::UploadClient;
40use crate::client::request::{CreateRequest, SendCreateUpload};
41
42use std::borrow::Cow;
43use std::fmt::{self, Formatter};
44use std::ops::Deref;
45
46#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
48pub struct ObjectUri {
49 pub bucket: Bucket,
53 pub key: Key,
55}
56
57impl ObjectUri {
58 pub fn new(bucket: Bucket, key: Key) -> Self {
60 Self { bucket, key }
61 }
62
63 pub(crate) fn is_empty(&self) -> bool {
64 self.bucket.is_empty() || self.key.is_empty()
65 }
66}
67
68impl fmt::Display for ObjectUri {
69 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
70 write!(f, "s3://{}/{}", &self.bucket, &self.key)
71 }
72}
73
74impl<T: Into<Bucket>, U: Into<Key>> From<(T, U)> for ObjectUri {
75 fn from((b, k): (T, U)) -> Self {
76 ObjectUri::new(b.into(), k.into())
77 }
78}
79
80#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
82pub struct Bucket(Cow<'static, str>);
83
84impl Bucket {
85 pub fn new<T: Into<Cow<'static, str>>>(bucket: T) -> Self {
87 let bucket: Cow<'static, str> = bucket.into();
88 match bucket.strip_suffix("/") {
89 Some(v) => v.into(),
90 _ => Self(bucket),
91 }
92 }
93
94 pub(crate) fn is_empty(&self) -> bool {
95 self.0.is_empty()
96 }
97}
98
99impl Deref for Bucket {
100 type Target = str;
101
102 fn deref(&self) -> &str {
103 &self.0
104 }
105}
106
107impl AsRef<str> for Bucket {
108 fn as_ref(&self) -> &str {
109 self
110 }
111}
112
113impl fmt::Display for Bucket {
114 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
115 self.0.fmt(f)
116 }
117}
118
119impl From<&str> for Bucket {
120 fn from(value: &str) -> Self {
121 Self::new(value.to_string())
122 }
123}
124
125impl From<String> for Bucket {
126 fn from(value: String) -> Self {
127 Self(Cow::Owned(value))
128 }
129}
130
131#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
133pub struct Key(Cow<'static, str>);
134
135impl Key {
136 pub fn new<T: Into<Cow<'static, str>>>(key: T) -> Self {
138 Self(key.into())
139 }
140
141 pub(crate) fn is_empty(&self) -> bool {
142 self.0.is_empty()
143 }
144}
145
146impl Deref for Key {
147 type Target = str;
148
149 fn deref(&self) -> &str {
150 &self.0
151 }
152}
153
154impl AsRef<str> for Key {
155 fn as_ref(&self) -> &str {
156 self
157 }
158}
159
160impl fmt::Display for Key {
161 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
162 self.0.fmt(f)
163 }
164}
165
166impl From<&str> for Key {
167 fn from(value: &str) -> Self {
168 Self::new(value.to_string())
169 }
170}
171
172impl From<String> for Key {
173 fn from(value: String) -> Self {
174 Self(Cow::Owned(value))
175 }
176}
177
178#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
180pub struct KeyPrefix(Cow<'static, str>);
181
182impl KeyPrefix {
183 pub fn new<T: Into<Cow<'static, str>>>(prefix: T) -> Self {
187 let raw: Cow<'static, str> = prefix.into();
188 let trimmed = raw.trim_matches('/');
189 Self(format!("{trimmed}/").into())
190 }
191
192 pub fn append(&self, other: &KeyPrefix) -> Self {
194 format!("{self}{other}").into()
195 }
196
197 pub fn to_key(&self, suffix: &str) -> Key {
199 format!("{self}{suffix}").into()
200 }
201}
202
203impl Deref for KeyPrefix {
204 type Target = str;
205
206 fn deref(&self) -> &str {
207 &self.0
208 }
209}
210
211impl AsRef<str> for KeyPrefix {
212 fn as_ref(&self) -> &str {
213 self
214 }
215}
216
217impl fmt::Display for KeyPrefix {
218 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
219 self.0.fmt(f)
220 }
221}
222
223impl From<&str> for KeyPrefix {
224 fn from(value: &str) -> Self {
225 Self::new(value.to_string())
226 }
227}
228
229impl From<String> for KeyPrefix {
230 fn from(value: String) -> Self {
231 Self::new(value)
232 }
233}
234
235pub struct ObjectUriIter {
237 inner: Box<dyn Iterator<Item = ObjectUri>>,
238}
239
240impl ObjectUriIter {
241 pub fn new<I>(iter: I) -> Self
243 where
244 I: IntoIterator<Item = ObjectUri> + 'static,
245 {
246 Self {
247 inner: Box::new(iter.into_iter()),
248 }
249 }
250
251 pub fn next_upload(&mut self, client: &UploadClient) -> Option<SendCreateUpload> {
254 let uri = self.next()?;
255 let req = CreateRequest::new(uri);
256 let fut = SendCreateUpload::new(client, req);
257 Some(fut)
258 }
259}
260
261impl Default for ObjectUriIter {
262 fn default() -> Self {
263 Self::new(EmptyUri)
264 }
265}
266
267impl Iterator for ObjectUriIter {
268 type Item = ObjectUri;
269 fn next(&mut self) -> Option<Self::Item> {
270 self.inner.next()
271 }
272}
273
274impl fmt::Debug for ObjectUriIter {
275 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
276 f.debug_struct("ObjectUriIter")
277 .field("inner", &"Iterator<Item = ObjectUri>")
278 .finish()
279 }
280}
281
282pub trait ObjectUriIterExt: Iterator {
284 fn map_key<B, F>(self, bucket: B, f: F) -> MapKey<Self, F>
287 where
288 Self: Iterator<Item = KeyPrefix> + Sized,
289 F: FnMut(KeyPrefix) -> Key,
290 B: Into<Bucket>,
291 {
292 MapKey::new(self, bucket, f)
293 }
294}
295
296impl<I: Iterator> ObjectUriIterExt for I {}
297
298pub struct MapKey<I, F> {
300 bucket: Bucket,
301 inner: I,
302 f: F,
303}
304
305impl<I, F> MapKey<I, F> {
306 fn new<B: Into<Bucket>>(inner: I, bucket: B, f: F) -> Self {
307 Self {
308 inner,
309 bucket: bucket.into(),
310 f,
311 }
312 }
313}
314
315impl<I, F> Iterator for MapKey<I, F>
316where
317 I: Iterator<Item = KeyPrefix>,
318 F: FnMut(KeyPrefix) -> Key,
319{
320 type Item = ObjectUri;
321
322 fn next(&mut self) -> Option<Self::Item> {
323 let prefix = self.inner.next()?;
324 let key = (self.f)(prefix);
325 let uri = ObjectUri::new(self.bucket.clone(), key);
326 Some(uri)
327 }
328}
329
330#[derive(Debug, Clone, Copy, Default)]
332pub struct EmptyUri;
333impl IntoIterator for EmptyUri {
334 type IntoIter = std::iter::Empty<ObjectUri>;
335 type Item = ObjectUri;
336
337 fn into_iter(self) -> Self::IntoIter {
338 std::iter::empty()
339 }
340}
341
342#[derive(Debug, Clone, Default)]
344pub struct OneTimeUse(Option<ObjectUri>);
345
346impl OneTimeUse {
347 pub fn new(uri: ObjectUri) -> Self {
349 Self(Some(uri))
350 }
351}
352
353impl Iterator for OneTimeUse {
354 type Item = ObjectUri;
355 fn next(&mut self) -> Option<Self::Item> {
356 self.0.take()
357 }
358}