use std::{
sync::Arc,
default::Default,
ops::{Deref, DerefMut}
};
#[cfg(feature="serde")]
use serde::{
Serialize, Deserialize,
ser::{Serializer},
de::{Deserializer}
};
use internals::bind::{base64, quoted_printable};
use headers::header_components::{
MediaType,
FileMeta,
TransferEncoding,
ContentId
};
#[derive(Debug, Clone)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct Metadata {
#[cfg_attr(feature="serde", serde(flatten))]
pub file_meta: FileMeta,
pub media_type: MediaType,
pub content_id: ContentId
}
impl Deref for Metadata {
type Target = FileMeta;
fn deref(&self) -> &Self::Target {
&self.file_meta
}
}
impl DerefMut for Metadata {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.file_meta
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct Data {
#[cfg_attr(feature="serde", serde(with="arc_buffer_serde"))]
buffer: Arc<[u8]>,
#[cfg_attr(feature="serde", serde(flatten))]
#[cfg_attr(feature="serde", serde(with="arc_serde"))]
meta: Arc<Metadata>
}
impl Data {
pub fn new(
buffer: impl Into<Arc<[u8]>>,
meta: impl Into<Arc<Metadata>>
) -> Self {
Data {
buffer: buffer.into(),
meta: meta.into()
}
}
pub fn plain_text(text: impl Into<String>, cid: ContentId) -> Data {
let text = text.into();
let buf = text.into_bytes();
let meta = Metadata {
file_meta: Default::default(),
media_type: MediaType::parse("text/plain; charset=utf-8").unwrap(),
content_id: cid
};
Self::new(buf, meta)
}
pub fn buffer(&self) -> &Arc<[u8]> {
&self.buffer
}
pub fn metadata(&self) -> &Arc<Metadata> {
&self.meta
}
pub fn file_meta(&self) -> &FileMeta {
&self.meta.file_meta
}
pub fn media_type(&self) -> &MediaType {
&self.meta.media_type
}
pub fn content_id(&self) -> &ContentId {
&self.meta.content_id
}
#[inline(always)]
pub fn transfer_encode(
&self,
encoding_hint: TransferEncodingHint,
) -> EncData {
transfer_encode(self, encoding_hint)
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub struct EncData {
#[cfg_attr(feature="serde", serde(with="arc_buffer_serde"))]
buffer: Arc<[u8]>,
#[cfg_attr(feature="serde", serde(flatten))]
#[cfg_attr(feature="serde", serde(with="arc_serde"))]
meta: Arc<Metadata>,
encoding: TransferEncoding
}
impl EncData {
pub(crate) fn new(
buffer: impl Into<Arc<[u8]>>,
meta: impl Into<Arc<Metadata>>,
encoding: TransferEncoding
) -> Self {
EncData {
buffer: buffer.into(),
meta: meta.into(),
encoding
}
}
pub fn transfer_encoded_buffer(&self) -> &Arc<[u8]> {
&self.buffer
}
pub fn metadata(&self) -> &Arc<Metadata> {
&self.meta
}
pub fn file_meta(&self) -> &FileMeta {
&self.meta.file_meta
}
pub fn media_type(&self) -> &MediaType {
&self.meta.media_type
}
pub fn encoding(&self) -> TransferEncoding {
self.encoding
}
pub fn content_id(&self) -> &ContentId {
&self.meta.content_id
}
}
#[derive(Debug, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
pub enum TransferEncodingHint {
UseBase64,
UseQuotedPrintable,
NoHint,
#[cfg_attr(feature="serde", serde(skip))]
#[doc(hidden)]
__NonExhaustive { }
}
impl Default for TransferEncodingHint {
fn default() -> Self {
TransferEncodingHint::UseBase64
}
}
fn transfer_encode(
data: &Data,
encoding_hint: TransferEncodingHint,
) -> EncData {
use self::TransferEncodingHint::*;
match encoding_hint {
UseQuotedPrintable => tenc_quoted_printable(data),
UseBase64 | NoHint => tenc_base64(data),
__NonExhaustive { .. } => panic!("__NonExhaustive encoding should not be passed to any place")
}
}
fn tenc_base64(data: &Data) -> EncData {
let enc_data = base64::normal_encode(data.buffer())
.into_bytes();
EncData::new(enc_data, data.metadata().clone(),
TransferEncoding::Base64)
}
fn tenc_quoted_printable(data: &Data) -> EncData {
let enc_data = quoted_printable::normal_encode(data.buffer())
.into_bytes();
EncData::new(enc_data, data.metadata().clone(),
TransferEncoding::QuotedPrintable)
}
#[cfg(feature="serde")]
mod arc_buffer_serde {
use super::*;
pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result<Arc<[u8]>, D::Error>
where D: Deserializer<'de>
{
let bytes = <Vec<u8>>::deserialize(deserializer)?;
Ok(bytes.into())
}
pub(crate) fn serialize<S>(data: &Arc<[u8]>, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(data)
}
}
#[cfg(feature="serde")]
mod arc_serde {
use super::*;
pub(crate) fn deserialize<'de, OUT, D>(deserializer: D) -> Result<Arc<OUT>, D::Error>
where D: Deserializer<'de>, OUT: Deserialize<'de>
{
let value = OUT::deserialize(deserializer)?;
Ok(Arc::new(value))
}
pub(crate) fn serialize<S, IN>(data: &Arc<IN>, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer, IN: Serialize
{
IN::serialize(&**data, serializer)
}
}