1use std::{num::NonZeroUsize, ops::Range};
2
3use serde::Serialize;
4
5use super::identity::{
6 AssetResolutionPolicyBinding, PostAssetSourceBinding, PostContentDigest,
7 PublicationAssetSourceBinding, bind_asset_resolution_policy,
8 bind_post_asset_source_with_content, bind_publication_asset_source, digest_post_content,
9};
10use super::{AssetRevisionReference, ExternalAssetOrigin, PostDocument, PublicationSettings};
11
12#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
14#[serde(transparent)]
15pub struct MarkdownDestinationOrdinal(NonZeroUsize);
16
17impl MarkdownDestinationOrdinal {
18 pub const fn get(self) -> usize {
19 self.0.get()
20 }
21
22 pub const fn new(value: NonZeroUsize) -> Self {
23 Self(value)
24 }
25}
26
27#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
29pub struct MarkdownSourceRange {
30 pub start: usize,
31 pub end: usize,
32}
33
34impl MarkdownSourceRange {
35 pub fn as_range(self) -> Range<usize> {
36 self.start..self.end
37 }
38
39 pub(super) const fn new(range: Range<usize>) -> Self {
40 Self {
41 start: range.start,
42 end: range.end,
43 }
44 }
45}
46
47#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
48#[serde(rename_all = "snake_case")]
49pub enum MarkdownDestinationKind {
50 Image,
51 Download,
52}
53
54#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Serialize)]
56#[serde(transparent)]
57pub struct AuthoredMarkdownDestination(Box<str>);
58
59impl AuthoredMarkdownDestination {
60 pub fn as_str(&self) -> &str {
61 &self.0
62 }
63
64 pub(super) fn new(value: &str) -> Self {
65 Self(value.into())
66 }
67}
68
69#[derive(Clone, Debug, Eq, PartialEq)]
71pub struct ResolvedMarkdownDestination {
72 pub ordinal: MarkdownDestinationOrdinal,
73 pub source_range: MarkdownSourceRange,
74 pub kind: MarkdownDestinationKind,
75 pub authored: AuthoredMarkdownDestination,
76 pub target: AssetRevisionReference,
77}
78
79impl ResolvedMarkdownDestination {
80 pub(super) fn new(
81 ordinal: MarkdownDestinationOrdinal,
82 source_range: MarkdownSourceRange,
83 kind: MarkdownDestinationKind,
84 authored: AuthoredMarkdownDestination,
85 target: AssetRevisionReference,
86 ) -> Self {
87 Self {
88 ordinal,
89 source_range,
90 kind,
91 authored,
92 target,
93 }
94 }
95}
96
97#[derive(Clone, Debug, Eq, PartialEq)]
99pub struct ResolvedPostAssets {
100 pub(super) source_binding: PostAssetSourceBinding,
101 pub(super) policy_binding: AssetResolutionPolicyBinding,
102 pub image: Option<AssetRevisionReference>,
103 pub references: Vec<AssetRevisionReference>,
104 pub markdown_destinations: Vec<ResolvedMarkdownDestination>,
105}
106
107impl ResolvedPostAssets {
108 pub fn new(
109 document: &PostDocument,
110 image: Option<AssetRevisionReference>,
111 references: Vec<AssetRevisionReference>,
112 ) -> Self {
113 Self::from_resolution(
114 document,
115 &digest_post_content(document),
116 &[],
117 image,
118 references,
119 Vec::new(),
120 )
121 }
122
123 pub(super) fn from_resolution(
124 document: &PostDocument,
125 content_digest: &PostContentDigest,
126 allowed_origins: &[ExternalAssetOrigin],
127 image: Option<AssetRevisionReference>,
128 references: Vec<AssetRevisionReference>,
129 markdown_destinations: Vec<ResolvedMarkdownDestination>,
130 ) -> Self {
131 Self {
132 source_binding: bind_post_asset_source_with_content(document, content_digest),
133 policy_binding: bind_asset_resolution_policy(allowed_origins),
134 image,
135 references,
136 markdown_destinations,
137 }
138 }
139
140 pub fn shares_policy_with(&self, site_assets: &ResolvedSiteAssets) -> bool {
141 self.policy_binding == site_assets.policy_binding
142 }
143}
144
145#[derive(Clone, Debug, Eq, PartialEq)]
147pub struct ResolvedSiteAssets {
148 pub(super) source_binding: PublicationAssetSourceBinding,
149 pub(super) policy_binding: AssetResolutionPolicyBinding,
150 pub favicon: Option<AssetRevisionReference>,
151 pub image: Option<AssetRevisionReference>,
152 pub allowed_origins: Vec<ExternalAssetOrigin>,
153 pub references: Vec<AssetRevisionReference>,
154}
155
156impl ResolvedSiteAssets {
157 pub fn new(
158 publication: &PublicationSettings,
159 favicon: Option<AssetRevisionReference>,
160 image: Option<AssetRevisionReference>,
161 allowed_origins: Vec<ExternalAssetOrigin>,
162 references: Vec<AssetRevisionReference>,
163 ) -> Self {
164 Self {
165 source_binding: bind_publication_asset_source(publication),
166 policy_binding: bind_asset_resolution_policy(&allowed_origins),
167 favicon,
168 image,
169 allowed_origins,
170 references,
171 }
172 }
173}