use std::{num::NonZeroUsize, ops::Range};
use serde::Serialize;
use super::identity::{
AssetResolutionPolicyBinding, PostAssetSourceBinding, PostContentDigest,
PublicationAssetSourceBinding, bind_asset_resolution_policy,
bind_post_asset_source_with_content, bind_publication_asset_source, digest_post_content,
};
use super::{AssetRevisionReference, ExternalAssetOrigin, PostDocument, PublicationSettings};
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
pub struct MarkdownDestinationOrdinal(NonZeroUsize);
impl MarkdownDestinationOrdinal {
pub const fn get(self) -> usize {
self.0.get()
}
pub const fn new(value: NonZeroUsize) -> Self {
Self(value)
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
pub struct MarkdownSourceRange {
pub start: usize,
pub end: usize,
}
impl MarkdownSourceRange {
pub fn as_range(self) -> Range<usize> {
self.start..self.end
}
pub(super) const fn new(range: Range<usize>) -> Self {
Self {
start: range.start,
end: range.end,
}
}
}
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum MarkdownDestinationKind {
Image,
Download,
}
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
#[serde(transparent)]
pub struct AuthoredMarkdownDestination(Box<str>);
impl AuthoredMarkdownDestination {
pub fn as_str(&self) -> &str {
&self.0
}
pub(super) fn new(value: &str) -> Self {
Self(value.into())
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ResolvedMarkdownDestination {
pub ordinal: MarkdownDestinationOrdinal,
pub source_range: MarkdownSourceRange,
pub kind: MarkdownDestinationKind,
pub authored: AuthoredMarkdownDestination,
pub target: AssetRevisionReference,
}
impl ResolvedMarkdownDestination {
pub(super) fn new(
ordinal: MarkdownDestinationOrdinal,
source_range: MarkdownSourceRange,
kind: MarkdownDestinationKind,
authored: AuthoredMarkdownDestination,
target: AssetRevisionReference,
) -> Self {
Self {
ordinal,
source_range,
kind,
authored,
target,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ResolvedPostAssets {
pub(super) source_binding: PostAssetSourceBinding,
pub(super) policy_binding: AssetResolutionPolicyBinding,
pub image: Option<AssetRevisionReference>,
pub references: Vec<AssetRevisionReference>,
pub markdown_destinations: Vec<ResolvedMarkdownDestination>,
}
impl ResolvedPostAssets {
pub fn new(
document: &PostDocument,
image: Option<AssetRevisionReference>,
references: Vec<AssetRevisionReference>,
) -> Self {
Self::from_resolution(
document,
&digest_post_content(document),
&[],
image,
references,
Vec::new(),
)
}
pub(super) fn from_resolution(
document: &PostDocument,
content_digest: &PostContentDigest,
allowed_origins: &[ExternalAssetOrigin],
image: Option<AssetRevisionReference>,
references: Vec<AssetRevisionReference>,
markdown_destinations: Vec<ResolvedMarkdownDestination>,
) -> Self {
Self {
source_binding: bind_post_asset_source_with_content(document, content_digest),
policy_binding: bind_asset_resolution_policy(allowed_origins),
image,
references,
markdown_destinations,
}
}
pub fn shares_policy_with(&self, site_assets: &ResolvedSiteAssets) -> bool {
self.policy_binding == site_assets.policy_binding
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct ResolvedSiteAssets {
pub(super) source_binding: PublicationAssetSourceBinding,
pub(super) policy_binding: AssetResolutionPolicyBinding,
pub favicon: Option<AssetRevisionReference>,
pub image: Option<AssetRevisionReference>,
pub allowed_origins: Vec<ExternalAssetOrigin>,
pub references: Vec<AssetRevisionReference>,
}
impl ResolvedSiteAssets {
pub fn new(
publication: &PublicationSettings,
favicon: Option<AssetRevisionReference>,
image: Option<AssetRevisionReference>,
allowed_origins: Vec<ExternalAssetOrigin>,
references: Vec<AssetRevisionReference>,
) -> Self {
Self {
source_binding: bind_publication_asset_source(publication),
policy_binding: bind_asset_resolution_policy(&allowed_origins),
favicon,
image,
allowed_origins,
references,
}
}
}