Skip to content

Commit 193f733

Browse files
committed
fix: fixed active/global state fallbacks
1 parent 68a467c commit 193f733

File tree

1 file changed

+102
-48
lines changed

1 file changed

+102
-48
lines changed

packages/perseus/src/template/render_ctx.rs

+102-48
Original file line numberDiff line numberDiff line change
@@ -74,11 +74,9 @@ impl RenderCtx {
7474

7575
Ok(())
7676
}
77-
/// Gets either the active state or the frozen state for the given page. If `.thaw()` has been called, thaw preferences will be registered, which this will use to decide whether to use
78-
/// frozen or active state. If neither is available, the caller should use generated state instead.
79-
///
80-
/// This takes a single type parameter for the reactive state type, from which the unreactive state type can be derived.
81-
pub fn get_active_or_frozen_page_state<R>(
77+
/// An internal getter for the frozen state for the given page. When this is called, it will also add any frozen state
78+
/// it finds to the page state store, overriding what was already there.
79+
fn get_frozen_page_state_and_register<R>(
8280
&mut self,
8381
url: &str,
8482
) -> Option<<R::Unrx as MakeRx>::Rx>
@@ -99,9 +97,7 @@ impl RenderCtx {
9997
Ok(unrx) => unrx,
10098
// The frozen state could easily be corrupted, so we'll fall back to the active state (which is already reactive)
10199
// We break out here to avoid double-storing this and trying to make a reactive thing reactive
102-
Err(_) => {
103-
return self.page_state_store.get::<<R::Unrx as MakeRx>::Rx>(url)
104-
}
100+
Err(_) => return None,
105101
};
106102
// This returns the reactive version of the unreactive version of `R`, which is why we have to make everything else do the same
107103
// Then we convince the compiler that that actually is `R` with the ludicrous trait bound at the beginning of this function
@@ -121,17 +117,60 @@ impl RenderCtx {
121117
None => self.page_state_store.get::<<R::Unrx as MakeRx>::Rx>(url),
122118
}
123119
} else {
124-
// The page state store stores the reactive state already, so we don't need to do anything more
125-
self.page_state_store.get::<<R::Unrx as MakeRx>::Rx>(url)
120+
None
121+
}
122+
} else {
123+
None
124+
}
125+
}
126+
/// An internal getter for the active (already registered) state for the given page.
127+
fn get_active_page_state<R>(&self, url: &str) -> Option<<R::Unrx as MakeRx>::Rx>
128+
where
129+
R: Clone + AnyFreeze + MakeUnrx,
130+
// We need this so that the compiler understands that the reactive version of the unreactive version of `R` has the same properties as `R` itself
131+
<<R as MakeUnrx>::Unrx as MakeRx>::Rx: Clone + AnyFreeze + MakeUnrx,
132+
{
133+
self.page_state_store.get::<<R::Unrx as MakeRx>::Rx>(url)
134+
}
135+
/// Gets either the active state or the frozen state for the given page. If `.thaw()` has been called, thaw preferences will be registered, which this will use to decide whether to use
136+
/// frozen or active state. If neither is available, the caller should use generated state instead.
137+
///
138+
/// This takes a single type parameter for the reactive state type, from which the unreactive state type can be derived.
139+
pub fn get_active_or_frozen_page_state<R>(
140+
&mut self,
141+
url: &str,
142+
) -> Option<<R::Unrx as MakeRx>::Rx>
143+
where
144+
R: Clone + AnyFreeze + MakeUnrx,
145+
// We need this so that the compiler understands that the reactive version of the unreactive version of `R` has the same properties as `R` itself
146+
<<R as MakeUnrx>::Unrx as MakeRx>::Rx: Clone + AnyFreeze + MakeUnrx,
147+
{
148+
let frozen_app_full = self.frozen_app.borrow();
149+
if let Some((_, thaw_prefs)) = &*frozen_app_full {
150+
// Check against the thaw preferences if we should prefer frozen state over active state
151+
if thaw_prefs.page.should_use_frozen_state(url) {
152+
drop(frozen_app_full);
153+
// We'll fall back to active state if no frozen state is available
154+
match self.get_frozen_page_state_and_register::<R>(url) {
155+
Some(state) => Some(state),
156+
None => self.get_active_page_state::<R>(url),
157+
}
158+
} else {
159+
drop(frozen_app_full);
160+
// We're preferring active state, but we'll fall back to frozen state if none is available
161+
match self.get_active_page_state::<R>(url) {
162+
Some(state) => Some(state),
163+
None => self.get_frozen_page_state_and_register::<R>(url),
164+
}
126165
}
127166
} else {
128167
// No frozen state exists, so we of course shouldn't prioritize it
129-
// The page state store stores the reactive state already, so we don't need to do anything more
130-
self.page_state_store.get::<<R::Unrx as MakeRx>::Rx>(url)
168+
self.get_active_page_state::<R>(url)
131169
}
132170
}
133-
/// Gets either the active or the frozen global state, depending on thaw preferences. Otherwise, this is exactly the same as `.get_active_or_frozen_state()`.
134-
pub fn get_active_or_frozen_global_state<R>(&mut self) -> Option<<R::Unrx as MakeRx>::Rx>
171+
/// An internal getter for the frozen global state. When this is called, it will also add any frozen state to the registered
172+
/// global state, removing whatever was there before.
173+
fn get_frozen_global_state_and_register<R>(&mut self) -> Option<<R::Unrx as MakeRx>::Rx>
135174
where
136175
R: Clone + AnyFreeze + MakeUnrx,
137176
// We need this so that the compiler understands that the reactive version of the unreactive version of `R` has the same properties as `R` itself
@@ -143,29 +182,14 @@ impl RenderCtx {
143182
if thaw_prefs.global_prefer_frozen {
144183
// Get the serialized and unreactive frozen state from the store
145184
match frozen_app.global_state.as_str() {
146-
// If there's nothing in the frozen state, we'll fall back to the active state
147-
"None" => self
148-
.global_state
149-
.0
150-
.borrow()
151-
.as_any()
152-
.downcast_ref::<<R::Unrx as MakeRx>::Rx>()
153-
.cloned(),
185+
// See `rx_state.rs` for why this would be the default value
186+
"None" => None,
154187
state_str => {
155188
// Deserialize into the unreactive version
156189
let unrx = match serde_json::from_str::<R::Unrx>(state_str) {
157190
Ok(unrx) => unrx,
158-
// The frozen state could easily be corrupted, so we'll fall back to the active state (which is already reactive)
159-
// We break out here to avoid double-storing this and trying to make a reactive thing reactive
160-
Err(_) => {
161-
return self
162-
.global_state
163-
.0
164-
.borrow()
165-
.as_any()
166-
.downcast_ref::<<R::Unrx as MakeRx>::Rx>()
167-
.cloned()
168-
}
191+
// The frozen state could easily be corrupted
192+
Err(_) => return None,
169193
};
170194
// This returns the reactive version of the unreactive version of `R`, which is why we have to make everything else do the same
171195
// Then we convince the compiler that that actually is `R` with the ludicrous trait bound at the beginning of this function
@@ -184,24 +208,54 @@ impl RenderCtx {
184208
}
185209
}
186210
} else {
187-
// The page state store stores the reactive state already, so we don't need to do anything more
188-
self.global_state
189-
.0
190-
.borrow()
191-
.as_any()
192-
.downcast_ref::<<R::Unrx as MakeRx>::Rx>()
193-
.cloned()
211+
None
212+
}
213+
} else {
214+
None
215+
}
216+
}
217+
/// An internal getter for the active (already registered) global state.
218+
fn get_active_global_state<R>(&self) -> Option<<R::Unrx as MakeRx>::Rx>
219+
where
220+
R: Clone + AnyFreeze + MakeUnrx,
221+
// We need this so that the compiler understands that the reactive version of the unreactive version of `R` has the same properties as `R` itself
222+
<<R as MakeUnrx>::Unrx as MakeRx>::Rx: Clone + AnyFreeze + MakeUnrx,
223+
{
224+
self.global_state
225+
.0
226+
.borrow()
227+
.as_any()
228+
.downcast_ref::<<R::Unrx as MakeRx>::Rx>()
229+
.cloned()
230+
}
231+
/// Gets either the active or the frozen global state, depending on thaw preferences. Otherwise, this is exactly the same as `.get_active_or_frozen_state()`.
232+
pub fn get_active_or_frozen_global_state<R>(&mut self) -> Option<<R::Unrx as MakeRx>::Rx>
233+
where
234+
R: Clone + AnyFreeze + MakeUnrx,
235+
// We need this so that the compiler understands that the reactive version of the unreactive version of `R` has the same properties as `R` itself
236+
<<R as MakeUnrx>::Unrx as MakeRx>::Rx: Clone + AnyFreeze + MakeUnrx,
237+
{
238+
let frozen_app_full = self.frozen_app.borrow();
239+
if let Some((_, thaw_prefs)) = &*frozen_app_full {
240+
// Check against the thaw preferences if we should prefer frozen state over active state
241+
if thaw_prefs.global_prefer_frozen {
242+
drop(frozen_app_full);
243+
// We'll fall back to the active state if there's no frozen state
244+
match self.get_frozen_global_state_and_register::<R>() {
245+
Some(state) => Some(state),
246+
None => self.get_active_global_state::<R>(),
247+
}
248+
} else {
249+
drop(frozen_app_full);
250+
// We'll fall back to the frozen state there's no active state available
251+
match self.get_active_global_state::<R>() {
252+
Some(state) => Some(state),
253+
None => self.get_frozen_global_state_and_register::<R>(),
254+
}
194255
}
195256
} else {
196257
// No frozen state exists, so we of course shouldn't prioritize it
197-
// This stores the reactive state already, so we don't need to do anything more
198-
// If we can't downcast the stored state to the user's type, it's almost certainly `None` instead (the initial value)
199-
self.global_state
200-
.0
201-
.borrow()
202-
.as_any()
203-
.downcast_ref::<<R::Unrx as MakeRx>::Rx>()
204-
.cloned()
258+
self.get_active_global_state::<R>()
205259
}
206260
}
207261
/// Registers a serialized and unreactive state string to the page state store, returning a fully reactive version.

0 commit comments

Comments
 (0)