use std::borrow::Cow;
use std::fmt::{self, Formatter};
use std::ops::Deref;
use std::sync::{Arc, Mutex};
use crate::client::UploadClient;
use crate::client::request::{CreateRequest, SendCreateUpload};
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct Bucket(Cow<'static, str>);
impl Bucket {
pub fn new<T: Into<Cow<'static, str>>>(bucket: T) -> Self {
let bucket: Cow<'static, str> = bucket.into();
match bucket.strip_suffix("/") {
Some(v) => v.into(),
_ => Self(bucket),
}
}
pub(crate) fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Deref for Bucket {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for Bucket {
fn as_ref(&self) -> &str {
self
}
}
impl fmt::Display for Bucket {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<&str> for Bucket {
fn from(value: &str) -> Self {
Self::new(value.to_string())
}
}
impl From<String> for Bucket {
fn from(value: String) -> Self {
Self(Cow::Owned(value))
}
}
impl From<Cow<'static, str>> for Bucket {
fn from(value: Cow<'static, str>) -> Self {
Self(value)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct Key(Cow<'static, str>);
impl Key {
pub fn new<T: Into<Cow<'static, str>>>(key: T) -> Self {
Self(key.into())
}
pub(crate) fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl Deref for Key {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for Key {
fn as_ref(&self) -> &str {
self
}
}
impl fmt::Display for Key {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<&str> for Key {
fn from(value: &str) -> Self {
Self::new(value.to_string())
}
}
impl From<String> for Key {
fn from(value: String) -> Self {
Self(Cow::Owned(value))
}
}
impl From<Cow<'static, str>> for Key {
fn from(value: Cow<'static, str>) -> Self {
Self(value)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct KeyPrefix(Cow<'static, str>);
impl KeyPrefix {
pub fn new<T: Into<Cow<'static, str>>>(prefix: T) -> Self {
let raw: Cow<'static, str> = prefix.into();
let trimmed = raw.trim_matches('/');
Self(format!("{trimmed}/").into())
}
pub fn root() -> Self {
KeyPrefix("/".into())
}
pub fn append(&self, other: &KeyPrefix) -> Self {
format!("{self}{other}").into()
}
pub fn to_key(&self, suffix: &str) -> Key {
format!("{self}{suffix}").into()
}
}
impl Deref for KeyPrefix {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for KeyPrefix {
fn as_ref(&self) -> &str {
self
}
}
impl fmt::Display for KeyPrefix {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<&str> for KeyPrefix {
fn from(value: &str) -> Self {
Self::new(value.to_string())
}
}
impl From<String> for KeyPrefix {
fn from(value: String) -> Self {
Self::new(value)
}
}
impl From<Cow<'static, str>> for KeyPrefix {
fn from(value: Cow<'static, str>) -> Self {
Self(value)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
pub struct ObjectUri {
pub bucket: Bucket,
pub key: Key,
}
impl ObjectUri {
pub fn new<B: Into<Bucket>, K: Into<Key>>(bucket: B, key: K) -> Self {
Self { bucket: bucket.into(), key: key.into() }
}
pub fn bucket(&self) -> &Bucket {
&self.bucket
}
pub fn key(&self) -> &Key {
&self.key
}
pub(crate) fn is_empty(&self) -> bool {
self.bucket.is_empty() || self.key.is_empty()
}
}
impl fmt::Display for ObjectUri {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "s3://{}/{}", &self.bucket, &self.key)
}
}
impl<T: Into<Bucket>, U: Into<Key>> From<(T, U)> for ObjectUri {
fn from((b, k): (T, U)) -> Self {
ObjectUri::new(b.into(), k.into())
}
}
#[derive(Clone)]
pub struct ObjectUriIter {
inner: Arc<Mutex<ObjectUriIterInner>>,
}
impl ObjectUriIter {
pub fn new<I>(iter: I) -> Self
where
I: Iterator<Item = ObjectUri> + Send + Sync + 'static,
{
let inner = ObjectUriIterInner(Box::new(iter));
Self { inner: Arc::new(Mutex::new(inner)) }
}
pub fn next_upload(
&mut self,
client: &UploadClient,
) -> Option<SendCreateUpload> {
let uri = self.next()?;
let req = CreateRequest::new(uri);
let fut = SendCreateUpload::new(client, req);
Some(fut)
}
}
impl Default for ObjectUriIter {
fn default() -> Self {
Self::new(EmptyUri.into_iter())
}
}
impl Iterator for ObjectUriIter {
type Item = ObjectUri;
fn next(&mut self) -> Option<Self::Item> {
let mut inner = self.inner.lock().unwrap();
inner.next()
}
}
impl fmt::Debug for ObjectUriIter {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("ObjectUriIter").finish()
}
}
pub trait ObjectUriIterExt: Iterator {
fn map_key<B, F>(self, bucket: B, f: F) -> MapKey<Self, F>
where
Self: Iterator<Item = KeyPrefix> + Sized,
F: FnMut(KeyPrefix) -> Key,
B: Into<Bucket>,
{
MapKey::new(self, bucket, f)
}
}
impl<I: Iterator> ObjectUriIterExt for I {}
pub struct MapKey<I, F> {
bucket: Bucket,
inner: I,
f: F,
}
impl<I, F> MapKey<I, F> {
fn new<B: Into<Bucket>>(inner: I, bucket: B, f: F) -> Self {
Self { inner, bucket: bucket.into(), f }
}
}
impl<I, F> Iterator for MapKey<I, F>
where
I: Iterator<Item = KeyPrefix>,
F: FnMut(KeyPrefix) -> Key,
{
type Item = ObjectUri;
fn next(&mut self) -> Option<Self::Item> {
let prefix = self.inner.next()?;
let key = (self.f)(prefix);
let uri = ObjectUri::new(self.bucket.clone(), key);
Some(uri)
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct EmptyUri;
impl IntoIterator for EmptyUri {
type IntoIter = std::iter::Empty<ObjectUri>;
type Item = ObjectUri;
fn into_iter(self) -> Self::IntoIter {
std::iter::empty()
}
}
#[derive(Debug, Clone, Default)]
pub struct OneTimeUse(Option<ObjectUri>);
impl OneTimeUse {
pub fn new(uri: ObjectUri) -> Self {
Self(Some(uri))
}
}
impl Iterator for OneTimeUse {
type Item = ObjectUri;
fn next(&mut self) -> Option<Self::Item> {
self.0.take()
}
}
struct ObjectUriIterInner(Box<dyn Iterator<Item = ObjectUri> + Send + Sync>);
impl ObjectUriIterInner {
fn next(&mut self) -> Option<ObjectUri> {
self.0.next()
}
}