use std::num::NonZeroU16;
use http::HeaderMap;
use super::{MultipartError, UploadId};
use crate::operation::{Checksum, Conditions, CopySource, ObjectKey, RequestIds};
use crate::stream::ByteStream;
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
pub struct PartNumber(NonZeroU16);
impl PartNumber {
pub const MAX: u16 = 10_000;
pub fn new(value: u16) -> Option<Self> {
NonZeroU16::new(value)
.filter(|value| value.get() <= Self::MAX)
.map(Self)
}
pub const fn get(self) -> u16 {
self.0.get()
}
}
#[derive(derive_more::Debug)]
pub struct UploadPartRequest {
key: ObjectKey,
upload_id: UploadId,
part_number: PartNumber,
#[debug("{:?}", "<stream>")]
body: ByteStream,
checksum: Checksum,
#[debug("{:?}", "<redacted>")]
pub headers: HeaderMap,
}
impl UploadPartRequest {
pub fn new(
key: ObjectKey,
upload_id: UploadId,
part_number: PartNumber,
body: ByteStream,
) -> Self {
Self {
key,
upload_id,
part_number,
body,
checksum: Checksum::default(),
headers: HeaderMap::new(),
}
}
pub fn with_headers(mut self, headers: HeaderMap) -> Self {
self.headers = headers;
self
}
pub const fn key(&self) -> &ObjectKey {
&self.key
}
pub const fn upload_id(&self) -> &UploadId {
&self.upload_id
}
pub const fn part_number(&self) -> PartNumber {
self.part_number
}
pub const fn body(&self) -> &ByteStream {
&self.body
}
pub fn body_mut(&mut self) -> &mut ByteStream {
&mut self.body
}
pub const fn checksum(&self) -> &Checksum {
&self.checksum
}
pub fn with_checksum(mut self, checksum: Checksum) -> Self {
self.checksum = checksum;
self
}
pub fn into_body(self) -> ByteStream {
self.body
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UploadPartOutput {
pub part_number: PartNumber,
pub e_tag: String,
pub checksum: Checksum,
pub request_ids: RequestIds,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct CopyPartRange {
start: u64,
end: u64,
}
impl CopyPartRange {
pub fn new(start: u64, end: u64) -> Result<Self, crate::operation::RangeError> {
if end < start {
return Err(crate::operation::RangeError { start, end });
}
Ok(Self { start, end })
}
pub const fn start(self) -> u64 {
self.start
}
pub const fn end(self) -> u64 {
self.end
}
pub(crate) fn header_value(self) -> String {
format!("bytes={}-{}", self.start, self.end)
}
}
#[derive(Clone, derive_more::Debug, Eq, PartialEq)]
pub struct UploadPartCopyRequest {
destination: ObjectKey,
upload_id: UploadId,
part_number: PartNumber,
pub source: CopySource,
pub source_range: Option<CopyPartRange>,
pub source_conditions: Conditions,
#[debug("{:?}", "<redacted>")]
pub headers: HeaderMap,
}
impl UploadPartCopyRequest {
pub fn new(
destination: ObjectKey,
upload_id: UploadId,
part_number: PartNumber,
source: CopySource,
) -> Self {
Self {
destination,
upload_id,
part_number,
source,
source_range: None,
source_conditions: Conditions::default(),
headers: HeaderMap::new(),
}
}
pub fn with_headers(mut self, headers: HeaderMap) -> Self {
self.headers = headers;
self
}
pub const fn destination(&self) -> &ObjectKey {
&self.destination
}
pub const fn upload_id(&self) -> &UploadId {
&self.upload_id
}
pub const fn part_number(&self) -> PartNumber {
self.part_number
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct UploadPartCopyOutput {
pub part_number: PartNumber,
pub e_tag: String,
pub last_modified: Option<time::OffsetDateTime>,
pub checksum: Checksum,
pub request_ids: RequestIds,
}
impl UploadPartCopyOutput {
pub fn completed_part(&self) -> Result<CompletedPart, MultipartError> {
CompletedPart::new(self.part_number.get(), self.e_tag.clone())
.map(|part| part.with_checksum(self.checksum.clone()))
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct CompletedPart {
part_number: PartNumber,
e_tag: String,
checksum: Checksum,
}
impl CompletedPart {
pub fn new(part_number: u16, e_tag: impl Into<String>) -> Result<Self, MultipartError> {
let part_number =
PartNumber::new(part_number).ok_or(MultipartError::InvalidPartNumber(part_number))?;
let e_tag = e_tag.into();
if e_tag.trim().is_empty() {
return Err(MultipartError::EmptyETag {
part_number: part_number.get(),
});
}
Ok(Self {
part_number,
e_tag,
checksum: Checksum::default(),
})
}
pub const fn part_number(&self) -> PartNumber {
self.part_number
}
pub fn e_tag(&self) -> &str {
&self.e_tag
}
pub const fn checksum(&self) -> &Checksum {
&self.checksum
}
pub fn with_checksum(mut self, checksum: Checksum) -> Self {
self.checksum = checksum;
self
}
}