pub mod derived_etag;
use std::ops::{Deref, DerefMut};
use headers::{ContentLength, ContentRange, ETag, LastModified};
use http_uri::HttpUri;
use typed_record::{ClonableTypedRecord, TypedRecord, TypedRecordKey};
use self::derived_etag::DerivedETag;
use crate::header::common::media_type::{MediaType, APPLICATION_OCTET_STREAM};
#[derive(Default, Clone)]
pub struct RepresentationMetadata(ClonableTypedRecord);
impl std::fmt::Debug for RepresentationMetadata {
#[inline]
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("RepresentationMetadata").finish()
}
}
impl Deref for RepresentationMetadata {
type Target = ClonableTypedRecord;
#[inline]
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RepresentationMetadata {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl RepresentationMetadata {
#[inline]
pub fn new() -> Self {
Self::default()
}
#[inline]
pub fn content_type(&self) -> &MediaType {
self.get_rv::<KContentType>()
.unwrap_or(&APPLICATION_OCTET_STREAM)
}
#[inline]
pub fn with<K: TypedRecordKey>(mut self, v: K::Value) -> Self
where
Self: Sized,
{
self.insert_rec_item::<K>(v);
self
}
#[inline]
pub fn with_opt<K: TypedRecordKey>(mut self, v: Option<K::Value>) -> Self
where
Self: Sized,
{
if let Some(v) = v {
self.insert_rec_item::<K>(v);
} else {
self.remove_rec_item::<K>();
}
self
}
}
#[cfg(feature = "impl-representation")]
mod rdf_ext {
use std::ops::Deref;
use rdf_dynsyn::{correspondence::Correspondent, syntax::RdfSyntax};
use super::RepresentationMetadata;
impl RepresentationMetadata {
#[inline]
pub fn rdf_syntax<S>(&self) -> Option<Correspondent<S>>
where
S: Deref<Target = RdfSyntax>,
Correspondent<S>: for<'a> TryFrom<&'a mime::Mime>,
{
Correspondent::try_from(self.content_type().deref()).ok()
}
}
}
#[derive(Debug, Clone)]
pub struct KContentType;
impl TypedRecordKey for KContentType {
type Value = MediaType;
}
#[derive(Debug, Clone)]
pub struct KCompleteContentLength;
impl TypedRecordKey for KCompleteContentLength {
type Value = ContentLength;
}
#[derive(Debug, Clone)]
pub struct KContentRange;
impl TypedRecordKey for KContentRange {
type Value = ContentRange;
}
#[derive(Debug, Clone)]
pub struct KLastModified;
impl TypedRecordKey for KLastModified {
type Value = LastModified;
}
#[derive(Debug, Clone)]
pub struct KETag;
impl TypedRecordKey for KETag {
type Value = ETag;
}
#[derive(Debug, Clone)]
pub struct KDerivedETag;
impl TypedRecordKey for KDerivedETag {
type Value = DerivedETag;
}
#[derive(Debug, Clone)]
pub struct KMd5;
impl TypedRecordKey for KMd5 {
type Value = String;
}
#[derive(Debug, Clone)]
pub struct KBaseUri;
impl TypedRecordKey for KBaseUri {
type Value = HttpUri;
}
#[cfg(feature = "test-utils")]
pub mod mock {
use std::ops::RangeBounds;
use chrono::{DateTime, Utc};
use claims::assert_ok;
use headers::ContentRange;
use typed_record::TypedRecord;
use super::{KContentRange, KContentType, KDerivedETag, KLastModified, RepresentationMetadata};
use crate::header::last_modified::LastModifiedExt;
pub trait RepresentationMetadataMockExt: seal::Sealed {
fn with_content_type(self, content_type_str: &str) -> Self;
fn with_last_modified(self, last_modified_rfc3339: &str) -> Self;
fn with_detag(self, derived_etag_str: &str) -> Self;
fn with_bytes_content_range(
self,
range: impl RangeBounds<u64>,
full_length: Option<u64>,
) -> Self;
}
impl RepresentationMetadataMockExt for RepresentationMetadata {
fn with_content_type(mut self, content_type_str: &str) -> Self {
let content_type = assert_ok!(content_type_str.parse());
self.insert_rec_item::<KContentType>(content_type);
self
}
fn with_last_modified(mut self, last_modified_rfc3339: &str) -> Self {
let last_modified = LastModifiedExt::from_date_time(assert_ok!(
DateTime::parse_from_rfc3339(last_modified_rfc3339)
.map(|dt| dt.with_timezone(&Utc))
));
self.insert_rec_item::<KLastModified>(last_modified);
self
}
fn with_detag(mut self, derived_etag_str: &str) -> Self {
let derived_etag = assert_ok!(derived_etag_str.parse());
self.insert_rec_item::<KDerivedETag>(derived_etag);
self
}
fn with_bytes_content_range(
mut self,
range: impl RangeBounds<u64>,
complete_length: Option<u64>,
) -> Self {
let content_rage = assert_ok!(ContentRange::bytes(range, complete_length));
self.insert_rec_item::<KContentRange>(content_rage);
self
}
}
mod seal {
use crate::representation::metadata::RepresentationMetadata;
pub trait Sealed {}
impl Sealed for RepresentationMetadata {}
}
}