coil_wasm/output/
cache.rs1use std::collections::BTreeSet;
2
3use crate::error::WasmModelError;
4use crate::validation::validate_token;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum CacheVisibility {
8 Public,
9 Private,
10}
11
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct TypedCacheHint {
14 pub visibility: CacheVisibility,
15 pub max_age_seconds: u64,
16 pub stale_while_revalidate_seconds: Option<u64>,
17 pub vary_by_locale: bool,
18 pub vary_by_user: bool,
19 pub vary_by_session: bool,
20 pub tags: BTreeSet<String>,
21}
22
23impl TypedCacheHint {
24 pub fn new(
25 visibility: CacheVisibility,
26 max_age_seconds: u64,
27 stale_while_revalidate_seconds: Option<u64>,
28 vary_by_locale: bool,
29 vary_by_user: bool,
30 vary_by_session: bool,
31 tags: impl IntoIterator<Item = impl Into<String>>,
32 ) -> Result<Self, WasmModelError> {
33 let tags = tags
34 .into_iter()
35 .map(|tag| validate_token("cache_tag", tag.into()))
36 .collect::<Result<BTreeSet<_>, _>>()?;
37 let hint = Self {
38 visibility,
39 max_age_seconds,
40 stale_while_revalidate_seconds,
41 vary_by_locale,
42 vary_by_user,
43 vary_by_session,
44 tags,
45 };
46 hint.validate()?;
47 Ok(hint)
48 }
49
50 pub(crate) fn validate(&self) -> Result<(), WasmModelError> {
51 if self.visibility == CacheVisibility::Public && (self.vary_by_user || self.vary_by_session)
52 {
53 return Err(WasmModelError::InvalidTypedReturn {
54 reason: "public cache hints cannot vary by user or session".to_string(),
55 });
56 }
57 if self
58 .stale_while_revalidate_seconds
59 .is_some_and(|value| value == 0)
60 {
61 return Err(WasmModelError::InvalidTypedReturn {
62 reason: "stale-while-revalidate must be greater than zero".to_string(),
63 });
64 }
65 for tag in &self.tags {
66 let _ = validate_token("cache_tag", tag.clone())?;
67 }
68 Ok(())
69 }
70
71 pub fn merge_from(&mut self, other: &Self) {
72 self.visibility = match (self.visibility, other.visibility) {
73 (CacheVisibility::Private, _) | (_, CacheVisibility::Private) => {
74 CacheVisibility::Private
75 }
76 _ => CacheVisibility::Public,
77 };
78 self.max_age_seconds = self.max_age_seconds.min(other.max_age_seconds);
79 self.stale_while_revalidate_seconds = match (
80 self.stale_while_revalidate_seconds,
81 other.stale_while_revalidate_seconds,
82 ) {
83 (Some(left), Some(right)) => Some(left.min(right)),
84 _ => None,
85 };
86 self.vary_by_locale |= other.vary_by_locale;
87 self.vary_by_user |= other.vary_by_user;
88 self.vary_by_session |= other.vary_by_session;
89 self.tags.extend(other.tags.iter().cloned());
90 }
91}