use std::borrow::Cow;
use std::collections::BTreeMap;
use std::fmt::{self, Display, Formatter};
use std::io::{Result as IoResult, Write};
use std::ops::{Deref, DerefMut};
use aws_sdk_s3::primitives::ByteStream;
use bytes::{BufMut as _, BytesMut};
use crate::complete_upload::CompleteMultipartUploadOutput as CompleteResponse;
use crate::error::{ErrorRepr, Result};
use crate::part_upload::UploadPartOutput as UploadResponse;
#[derive(Clone, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct PartBody(BytesMut);
impl PartBody {
pub fn new(bytes: BytesMut) -> Self {
Self(bytes)
}
pub fn with_capacity(capacity: usize) -> Self {
let bytes = BytesMut::with_capacity(capacity);
Self(bytes)
}
pub fn size(&self) -> usize {
self.0.len()
}
pub fn remove(&mut self) -> Self {
self.split().into()
}
pub fn as_sdk_body(&mut self) -> ByteStream {
let buf = self.split();
let bytes = buf.freeze();
bytes.into()
}
}
impl Write for PartBody {
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
let bytes = buf.len();
self.reserve(bytes);
self.put(buf);
Ok(bytes)
}
fn flush(&mut self) -> IoResult<()> {
Ok(())
}
}
impl From<BytesMut> for PartBody {
fn from(value: BytesMut) -> Self {
Self(value)
}
}
impl Deref for PartBody {
type Target = BytesMut;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PartBody {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl AsRef<[u8]> for PartBody {
fn as_ref(&self) -> &[u8] {
self.deref().as_ref()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PartNumber(i32);
impl PartNumber {
pub fn new() -> Self {
Self(1)
}
pub fn start_with(n: i32) -> Self {
Self(n)
}
pub fn is_first(&self) -> bool {
**self == 1
}
pub fn is_valid(&self) -> bool {
**self > 0
}
pub fn fetch_incr(&mut self) -> PartNumber {
let curr = PartNumber(self.0);
self.0 += 1;
curr
}
}
impl Default for PartNumber {
fn default() -> Self {
Self(1)
}
}
impl Deref for PartNumber {
type Target = i32;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for PartNumber {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl Display for PartNumber {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "part_{}", self.0)
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq, PartialOrd, Ord)]
pub struct EntityTag(Cow<'static, str>);
impl EntityTag {
fn new<T: Into<Cow<'static, str>>>(etag: T) -> Self {
Self(etag.into())
}
pub(crate) fn try_from_upload_resp(
value: &UploadResponse,
) -> Result<Self, ErrorRepr> {
value
.e_tag
.as_deref()
.map(Self::from)
.ok_or_else(|| ErrorRepr::Missing("UploadResponse", "e_tag"))
}
pub(crate) fn try_from_complete_resp(
value: &CompleteResponse,
) -> Result<Self, ErrorRepr> {
value
.e_tag
.as_deref()
.map(Self::from)
.ok_or_else(|| ErrorRepr::Missing("CompleteResponse", "e_tag"))
}
}
impl Deref for EntityTag {
type Target = str;
fn deref(&self) -> &str {
&self.0
}
}
impl AsRef<str> for EntityTag {
fn as_ref(&self) -> &str {
self
}
}
impl Display for EntityTag {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl From<&str> for EntityTag {
fn from(value: &str) -> Self {
Self::new(value.to_string())
}
}
impl From<String> for EntityTag {
fn from(value: String) -> Self {
Self(Cow::Owned(value))
}
}
#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd)]
pub struct CompletedPart {
pub etag: EntityTag,
pub part_number: PartNumber,
pub part_size: usize,
}
impl CompletedPart {
pub fn new(
etag: EntityTag,
part_number: PartNumber,
part_size: usize,
) -> Self {
Self { etag, part_number, part_size }
}
}
#[derive(Debug, Clone, Default)]
pub struct CompletedParts {
parts: BTreeMap<PartNumber, CompletedPart>,
total_bytes: usize,
}
impl CompletedParts {
pub fn insert(&mut self, part: CompletedPart) {
let k = part.part_number;
if !self.parts.contains_key(&k) {
self.total_bytes += part.part_size;
self.parts.insert(k, part);
}
}
pub fn append(&mut self, other: CompletedParts) {
other.parts.into_values().for_each(|v| {
self.insert(v);
})
}
pub fn count(&self) -> usize {
self.parts.len()
}
pub fn size(&self) -> usize {
self.total_bytes
}
}
impl From<&CompletedParts> for aws_sdk_s3::types::CompletedMultipartUpload {
fn from(vs: &CompletedParts) -> Self {
let parts = vs.parts.values().fold(Vec::new(), |mut acc, v| {
acc.push(
aws_sdk_s3::types::CompletedPart::builder()
.e_tag(&*v.etag)
.part_number(*v.part_number)
.build(),
);
acc
});
aws_sdk_s3::types::CompletedMultipartUpload::builder()
.set_parts(Some(parts))
.build()
}
}