1use crate::error::FactoryError;
19use crate::options::EntryOptions;
20use crate::tags::Tag;
21use crate::time::Timestamp;
22
23#[derive(Debug)]
28pub struct FactoryProduct<V> {
29 pub(crate) value: V,
30 pub(crate) options: EntryOptions,
31 pub(crate) etag: Option<String>,
32 pub(crate) last_modified: Option<Timestamp>,
33 pub(crate) tags: Box<[Tag]>,
34 pub(crate) reused_stale: bool,
37}
38
39impl<V> FactoryProduct<V> {
40 #[must_use]
42 pub fn value(&self) -> &V {
43 &self.value
44 }
45}
46
47#[derive(Debug)]
50pub struct FactoryContext<V> {
51 key: std::sync::Arc<str>,
52 options: EntryOptions,
53 call_tags: Box<[Tag]>,
54 adaptive_tags: Option<Box<[Tag]>>,
55 stale_value: Option<V>,
56 stale_etag: Option<String>,
57 stale_last_modified: Option<Timestamp>,
58 stale_tags: Box<[Tag]>,
59}
60
61impl<V> FactoryContext<V> {
62 pub(crate) fn new(
63 key: std::sync::Arc<str>,
64 options: EntryOptions,
65 call_tags: Box<[Tag]>,
66 stale: Option<StaleInfo<V>>,
67 ) -> Self {
68 let (stale_value, stale_etag, stale_last_modified, stale_tags) = match stale {
69 Some(s) => (Some(s.value), s.etag, s.last_modified, s.tags),
70 None => (None, None, None, Box::from([])),
71 };
72 Self {
73 key,
74 options,
75 call_tags,
76 adaptive_tags: None,
77 stale_value,
78 stale_etag,
79 stale_last_modified,
80 stale_tags,
81 }
82 }
83
84 #[must_use]
86 pub fn key(&self) -> &str {
87 &self.key
88 }
89
90 #[must_use]
94 pub fn options_mut(&mut self) -> &mut EntryOptions {
95 &mut self.options
96 }
97
98 #[must_use]
100 pub fn options(&self) -> &EntryOptions {
101 &self.options
102 }
103
104 pub fn adapt<F>(&mut self, f: F)
111 where
112 F: FnOnce(EntryOptions) -> EntryOptions,
113 {
114 let current = self.options.clone();
115 self.options = f(current);
116 }
117
118 #[must_use]
120 pub fn has_stale_value(&self) -> bool {
121 self.stale_value.is_some()
122 }
123
124 #[must_use]
126 pub fn stale_value(&self) -> Option<&V> {
127 self.stale_value.as_ref()
128 }
129
130 #[must_use]
132 pub fn stale_etag(&self) -> Option<&str> {
133 self.stale_etag.as_deref()
134 }
135
136 #[must_use]
138 pub fn stale_last_modified(&self) -> Option<Timestamp> {
139 self.stale_last_modified
140 }
141
142 pub fn set_tags<I, S>(&mut self, tags: I)
145 where
146 I: IntoIterator<Item = S>,
147 S: AsRef<str>,
148 {
149 self.adaptive_tags = Some(crate::tags::collect_tags(tags));
150 }
151
152 fn effective_tags(&self) -> Box<[Tag]> {
153 self.adaptive_tags
154 .clone()
155 .unwrap_or_else(|| self.call_tags.clone())
156 }
157
158 #[must_use]
160 pub fn value(self, value: V) -> FactoryProduct<V> {
161 let tags = self.effective_tags();
162 FactoryProduct {
163 value,
164 options: self.options,
165 etag: None,
166 last_modified: None,
167 tags,
168 reused_stale: false,
169 }
170 }
171
172 pub fn modified(self, value: V) -> ModifiedBuilder<V> {
175 ModifiedBuilder {
176 ctx: self,
177 value,
178 etag: None,
179 last_modified: None,
180 tags: None,
181 }
182 }
183
184 #[must_use]
187 pub fn fail(&self, message: impl Into<String>) -> FactoryError {
188 FactoryError::new(message)
189 }
190}
191
192impl<V: Clone> FactoryContext<V> {
193 pub fn not_modified(self) -> Result<FactoryProduct<V>, FactoryError> {
197 match &self.stale_value {
198 Some(value) => Ok(FactoryProduct {
199 value: value.clone(),
200 options: self.options.clone(),
201 etag: self.stale_etag.clone(),
202 last_modified: self.stale_last_modified,
203 tags: self.stale_tags.clone(),
204 reused_stale: true,
205 }),
206 None => Err(FactoryError::new(
207 "not_modified() was called but no stale value is available to reuse",
208 )),
209 }
210 }
211}
212
213pub(crate) struct StaleInfo<V> {
216 pub(crate) value: V,
217 pub(crate) etag: Option<String>,
218 pub(crate) last_modified: Option<Timestamp>,
219 pub(crate) tags: Box<[Tag]>,
220}
221
222#[derive(Debug)]
224#[must_use = "call `.done()` to produce the FactoryProduct"]
225pub struct ModifiedBuilder<V> {
226 ctx: FactoryContext<V>,
227 value: V,
228 etag: Option<String>,
229 last_modified: Option<Timestamp>,
230 tags: Option<Box<[Tag]>>,
231}
232
233impl<V> ModifiedBuilder<V> {
234 pub fn etag(mut self, etag: impl Into<String>) -> Self {
236 self.etag = Some(etag.into());
237 self
238 }
239
240 pub fn last_modified(mut self, last_modified: Timestamp) -> Self {
242 self.last_modified = Some(last_modified);
243 self
244 }
245
246 pub fn tags<I, S>(mut self, tags: I) -> Self
248 where
249 I: IntoIterator<Item = S>,
250 S: AsRef<str>,
251 {
252 self.tags = Some(crate::tags::collect_tags(tags));
253 self
254 }
255
256 #[must_use]
258 pub fn done(self) -> FactoryProduct<V> {
259 let tags = self.tags.unwrap_or_else(|| self.ctx.effective_tags());
260 FactoryProduct {
261 value: self.value,
262 options: self.ctx.options,
263 etag: self.etag,
264 last_modified: self.last_modified,
265 tags,
266 reused_stale: false,
267 }
268 }
269}