use std::pin::Pin;
use bytes::{Bytes, BytesMut};
use futures_core::Stream;
use futures_util::StreamExt;
use std::result::Result;
use crate::{signer::sha256_hash, utils::EMPTY_CONTENT_SHA256};
#[allow(unused)]
pub(crate) enum PayloadHash {
Checksum(String),
Unsigned,
Streaming,
StreamingTrailer,
EmptySha256,
}
impl PayloadHash {
pub fn checksum(hash: String) -> Self {
Self::Checksum(hash)
}
pub fn as_str(&self) -> &str {
match self {
PayloadHash::Checksum(v) => v.as_str(),
PayloadHash::EmptySha256 => EMPTY_CONTENT_SHA256,
PayloadHash::Unsigned => "UNSIGNED-PAYLOAD",
PayloadHash::Streaming => "STREAMING-AWS4-HMAC-SHA256-PAYLOAD",
PayloadHash::StreamingTrailer => "STREAMING-AWS4-HMAC-SHA256-PAYLOAD-TRAILER",
}
}
}
pub enum Data<E> {
Bytes(Bytes),
Stream(
Pin<Box<dyn Stream<Item = Result<Bytes, E>> + Sync + Send>>,
usize,
),
}
impl<E> Data<E> {
#[inline]
pub fn empty() -> Self {
Self::Bytes(Bytes::new())
}
pub async fn convert(self) -> Result<Self, E> {
Ok(match self {
Data::Stream(mut s, l) => {
let mut buf = BytesMut::with_capacity(l);
while let Some(data) = s.next().await {
buf.extend_from_slice(&data?);
}
Data::Bytes(buf.freeze())
}
_ => self,
})
}
#[inline]
pub fn len(&self) -> usize {
match self {
Data::Bytes(data) => data.len(),
Data::Stream(_, len) => len.clone(),
}
}
pub(crate) fn payload_hash(&self) -> PayloadHash {
match self {
Data::Stream(_, _) => PayloadHash::Streaming,
Data::Bytes(data) if data.len() == 0 => PayloadHash::EmptySha256,
Data::Bytes(data) => PayloadHash::checksum(sha256_hash(data)),
}
}
}
impl<E> Default for Data<E> {
fn default() -> Self {
Self::empty()
}
}
impl<E> From<Option<Bytes>> for Data<E> {
fn from(value: Option<Bytes>) -> Self {
match value {
Some(v) => Self::Bytes(v),
None => Self::empty(),
}
}
}
impl<E> From<Bytes> for Data<E> {
fn from(value: Bytes) -> Self {
Self::Bytes(value)
}
}
impl<E> From<String> for Data<E> {
fn from(value: String) -> Self {
Self::Bytes(value.into())
}
}
impl<E> From<&'static str> for Data<E> {
fn from(value: &'static str) -> Self {
Self::Bytes(value.into())
}
}
impl<E> From<Vec<u8>> for Data<E> {
fn from(value: Vec<u8>) -> Self {
Self::Bytes(value.into())
}
}
impl<E>
From<(
Pin<Box<dyn Stream<Item = Result<Bytes, E>> + Sync + Send>>,
usize,
)> for Data<E>
{
fn from(
value: (
Pin<Box<dyn Stream<Item = Result<Bytes, E>> + Sync + Send>>,
usize,
),
) -> Self {
Self::Stream(value.0, value.1)
}
}