rama_http/protocols/rss/rss2/
builder.rs1use std::marker::PhantomData;
2
3use jiff::Timestamp;
4use rama_net::uri::Uri;
5use rama_utils::macros::generate_set_and_with;
6
7use super::types::{Missing, Present, Rss2Category, Rss2Feed, Rss2Image, Rss2Item};
8use crate::protocols::rss::atom::AtomLink;
9use crate::protocols::rss::feed_ext::FeedExtensions;
10
11pub struct Rss2FeedBuilder<T, L, D> {
17 pub(super) title: String,
18 pub(super) link: Option<Uri>,
19 pub(super) description: String,
20 pub(super) language: Option<String>,
21 pub(super) copyright: Option<String>,
22 pub(super) managing_editor: Option<String>,
23 pub(super) web_master: Option<String>,
24 pub(super) pub_date: Option<Timestamp>,
25 pub(super) last_build_date: Option<Timestamp>,
26 pub(super) categories: Vec<Rss2Category>,
27 pub(super) generator: Option<String>,
28 pub(super) docs: Option<String>,
29 pub(super) ttl: Option<u32>,
30 pub(super) image: Option<Rss2Image>,
31 pub(super) atom_links: Vec<AtomLink>,
32 pub(super) items: Vec<Rss2Item>,
33 pub(super) extensions: FeedExtensions,
34 pub(super) _pd: PhantomData<(T, L, D)>,
35}
36
37impl Rss2FeedBuilder<Missing, Missing, Missing> {
38 pub(super) fn new() -> Self {
39 Self {
40 title: String::new(),
41 link: None,
42 description: String::new(),
43 language: None,
44 copyright: None,
45 managing_editor: None,
46 web_master: None,
47 pub_date: None,
48 last_build_date: None,
49 categories: Vec::new(),
50 generator: None,
51 docs: None,
52 ttl: None,
53 image: None,
54 atom_links: Vec::new(),
55 items: Vec::new(),
56 extensions: FeedExtensions::default(),
57 _pd: PhantomData,
58 }
59 }
60}
61
62impl<L, D> Rss2FeedBuilder<Missing, L, D> {
63 #[must_use]
64 pub fn title(self, title: impl Into<String>) -> Rss2FeedBuilder<Present, L, D> {
65 Rss2FeedBuilder {
66 title: title.into(),
67 link: self.link,
68 description: self.description,
69 language: self.language,
70 copyright: self.copyright,
71 managing_editor: self.managing_editor,
72 web_master: self.web_master,
73 pub_date: self.pub_date,
74 last_build_date: self.last_build_date,
75 categories: self.categories,
76 generator: self.generator,
77 docs: self.docs,
78 ttl: self.ttl,
79 image: self.image,
80 atom_links: self.atom_links,
81 items: self.items,
82 extensions: self.extensions,
83 _pd: PhantomData,
84 }
85 }
86}
87
88impl<T, D> Rss2FeedBuilder<T, Missing, D> {
89 #[must_use]
90 pub fn link(self, link: Uri) -> Rss2FeedBuilder<T, Present, D> {
91 Rss2FeedBuilder {
92 title: self.title,
93 link: Some(link),
94 description: self.description,
95 language: self.language,
96 copyright: self.copyright,
97 managing_editor: self.managing_editor,
98 web_master: self.web_master,
99 pub_date: self.pub_date,
100 last_build_date: self.last_build_date,
101 categories: self.categories,
102 generator: self.generator,
103 docs: self.docs,
104 ttl: self.ttl,
105 image: self.image,
106 atom_links: self.atom_links,
107 items: self.items,
108 extensions: self.extensions,
109 _pd: PhantomData,
110 }
111 }
112}
113
114impl<T, L> Rss2FeedBuilder<T, L, Missing> {
115 #[must_use]
116 pub fn description(self, desc: impl Into<String>) -> Rss2FeedBuilder<T, L, Present> {
117 Rss2FeedBuilder {
118 title: self.title,
119 link: self.link,
120 description: desc.into(),
121 language: self.language,
122 copyright: self.copyright,
123 managing_editor: self.managing_editor,
124 web_master: self.web_master,
125 pub_date: self.pub_date,
126 last_build_date: self.last_build_date,
127 categories: self.categories,
128 generator: self.generator,
129 docs: self.docs,
130 ttl: self.ttl,
131 image: self.image,
132 atom_links: self.atom_links,
133 items: self.items,
134 extensions: self.extensions,
135 _pd: PhantomData,
136 }
137 }
138}
139
140impl<T, L, D> Rss2FeedBuilder<T, L, D> {
141 generate_set_and_with! {
142 pub fn language(mut self, lang: impl Into<String>) -> Self {
143 self.language = Some(lang.into());
144 self
145 }
146 }
147
148 generate_set_and_with! {
149 pub fn copyright(mut self, copyright: impl Into<String>) -> Self {
150 self.copyright = Some(copyright.into());
151 self
152 }
153 }
154
155 generate_set_and_with! {
156 pub fn managing_editor(mut self, editor: impl Into<String>) -> Self {
157 self.managing_editor = Some(editor.into());
158 self
159 }
160 }
161
162 generate_set_and_with! {
163 pub fn web_master(mut self, wm: impl Into<String>) -> Self {
164 self.web_master = Some(wm.into());
165 self
166 }
167 }
168
169 generate_set_and_with! {
170 pub fn pub_date(mut self, date: Timestamp) -> Self {
171 self.pub_date = Some(date);
172 self
173 }
174 }
175
176 generate_set_and_with! {
177 pub fn last_build_date(mut self, date: Timestamp) -> Self {
178 self.last_build_date = Some(date);
179 self
180 }
181 }
182
183 generate_set_and_with! {
184 pub fn category(mut self, cat: Rss2Category) -> Self {
186 self.categories.push(cat);
187 self
188 }
189 }
190
191 generate_set_and_with! {
192 pub fn generator(mut self, generator: impl Into<String>) -> Self {
193 self.generator = Some(generator.into());
194 self
195 }
196 }
197
198 generate_set_and_with! {
199 pub fn docs(mut self, docs: impl Into<String>) -> Self {
203 self.docs = Some(docs.into());
204 self
205 }
206 }
207
208 generate_set_and_with! {
209 pub fn ttl(mut self, ttl: u32) -> Self {
210 self.ttl = Some(ttl);
211 self
212 }
213 }
214
215 generate_set_and_with! {
216 pub fn image(mut self, image: Rss2Image) -> Self {
217 self.image = Some(image);
218 self
219 }
220 }
221
222 generate_set_and_with! {
223 pub fn atom_link(mut self, link: AtomLink) -> Self {
227 self.atom_links.push(link);
228 self
229 }
230 }
231
232 generate_set_and_with! {
233 pub fn item(mut self, item: Rss2Item) -> Self {
235 self.items.push(item);
236 self
237 }
238 }
239
240 generate_set_and_with! {
241 pub fn items(mut self, items: impl IntoIterator<Item = Rss2Item>) -> Self {
242 self.items.extend(items);
243 self
244 }
245 }
246
247 generate_set_and_with! {
248 pub fn feed_extensions(mut self, ext: FeedExtensions) -> Self {
249 self.extensions = ext;
250 self
251 }
252 }
253}
254
255impl Rss2FeedBuilder<Present, Present, Present> {
256 #[must_use]
257 pub fn build(self) -> Rss2Feed {
258 Rss2Feed {
259 title: self.title,
260 #[expect(
261 clippy::expect_used,
262 reason = "type-state guarantees `link` is Present once build() is callable"
263 )]
264 link: self.link.expect("link is Present"),
265 description: self.description,
266 language: self.language,
267 copyright: self.copyright,
268 managing_editor: self.managing_editor,
269 web_master: self.web_master,
270 pub_date: self.pub_date,
271 last_build_date: self.last_build_date,
272 categories: self.categories,
273 generator: self.generator,
274 docs: self.docs,
275 ttl: self.ttl,
276 image: self.image,
277 atom_links: self.atom_links,
278 items: self.items,
279 extensions: self.extensions,
280 }
281 }
282}