Skip to content

Commit ddeda82

Browse files
committed
wip: redesign csr
1 parent b35076b commit ddeda82

File tree

50 files changed

+4326
-2049
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+4326
-2049
lines changed

packages/frender-common/src/either.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
mod element;
2+
pub use element::EitherElement;
3+
14
pub enum EitherState<L, R> {
25
Left { inner: L },
36
Right { inner: R },
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#[derive(Debug, Clone, Copy)]
2+
pub enum EitherElement<A, B> {
3+
A(A),
4+
B(B),
5+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
use frender_ssr::SsrElement;
2+
3+
use crate::{ContextKey, ContextKeyInner};
4+
5+
// TODO: `state_unmount()` doesn't get the correct context value. Is this a problem?
6+
pub mod csr;
7+
mod ssr;
8+
9+
impl<T, Inner: ContextKeyInner<Value = T>> ContextKey<Inner> {
10+
/// Shortcut for <code>CTX.[value](Self::value)(value).[children](ElementWithContext::children)(get_element)</code>
11+
pub fn provide<E: SsrElement, FE: FnOnce() -> E>(
12+
&'static self,
13+
value: T,
14+
get_element: FE,
15+
) -> ElementWithContext<Inner, Value<T>, FE> {
16+
ElementWithContext {
17+
context_key: self,
18+
into_value: Value(value),
19+
get_element,
20+
}
21+
}
22+
23+
/// Shortcut for <code>CTX.[get_value](Self::get_value)(get_value).[children](ElementWithContext::children)(get_element)</code>
24+
pub fn provide_with<F: FnOnce() -> T, E: SsrElement, FE: FnOnce() -> E>(
25+
&'static self,
26+
get_value: F,
27+
get_element: FE,
28+
) -> ElementWithContext<Inner, GetValue<F>, FE> {
29+
ElementWithContext {
30+
context_key: self,
31+
into_value: GetValue(get_value),
32+
get_element,
33+
}
34+
}
35+
36+
pub fn value(&'static self, value: T) -> ElementWithContext<Inner, Value<T>, ()> {
37+
ElementWithContext {
38+
context_key: self,
39+
into_value: Value(value),
40+
get_element: (),
41+
}
42+
}
43+
44+
pub fn get_value<F: FnOnce() -> T>(
45+
&'static self,
46+
get_value: F,
47+
) -> ElementWithContext<Inner, GetValue<F>, ()> {
48+
ElementWithContext {
49+
context_key: self,
50+
into_value: GetValue(get_value),
51+
get_element: (),
52+
}
53+
}
54+
}
55+
56+
pub trait IntoContextValue {
57+
type ContextValue;
58+
59+
fn into_context_value(self) -> Self::ContextValue;
60+
fn update_context_value_lazily(self, value: &mut Self::ContextValue);
61+
}
62+
63+
pub struct Value<T>(pub T);
64+
pub struct GetValue<F>(pub F);
65+
66+
impl<T> IntoContextValue for Value<T> {
67+
type ContextValue = T;
68+
69+
fn into_context_value(self) -> Self::ContextValue {
70+
self.0
71+
}
72+
73+
fn update_context_value_lazily(self, value: &mut Self::ContextValue) {
74+
*value = self.0;
75+
}
76+
}
77+
78+
impl<F: FnOnce() -> T, T> IntoContextValue for GetValue<F> {
79+
type ContextValue = T;
80+
81+
fn into_context_value(self) -> Self::ContextValue {
82+
self.0()
83+
}
84+
85+
fn update_context_value_lazily(self, _: &mut Self::ContextValue) {
86+
// Doesn't update context value
87+
}
88+
}
89+
90+
pub struct ElementWithContext<
91+
Inner: ContextKeyInner + 'static,
92+
F: IntoContextValue<ContextValue = Inner::Value>,
93+
FE,
94+
> {
95+
pub context_key: &'static ContextKey<Inner>,
96+
pub into_value: F,
97+
pub get_element: FE,
98+
}
99+
100+
impl<T, Inner: ContextKeyInner<Value = T> + 'static, F: IntoContextValue<ContextValue = T>>
101+
ElementWithContext<Inner, F, ()>
102+
{
103+
pub fn children<E: SsrElement, FE: FnOnce() -> E>(
104+
self,
105+
get_element: FE,
106+
) -> ElementWithContext<Inner, F, FE> {
107+
let Self {
108+
context_key,
109+
into_value,
110+
get_element: (),
111+
} = self;
112+
ElementWithContext {
113+
context_key,
114+
into_value,
115+
get_element,
116+
}
117+
}
118+
}
Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
use std::{marker::PhantomData, task::Poll};
2+
3+
use frender_html::{
4+
experimental::{
5+
self, PinnedRenderStateKind, PinnedRenderStateKindPollRender, RenderStates,
6+
UnpinnedRenderStateKind, UnpinnedRenderStateKindPollRender,
7+
},
8+
kinds::UiHandleWithNonReactiveState,
9+
CsrElement, RenderHtml,
10+
};
11+
12+
use crate::{ContextKey, ContextKeyInner};
13+
14+
use super::{ElementWithContext, IntoContextValue};
15+
16+
pub struct ContextKeyAndValue<C: ContextKeyInner + 'static> {
17+
context_key: &'static ContextKey<C>,
18+
value: C::SwapValue,
19+
}
20+
21+
impl<C: ContextKeyInner + 'static> ContextKeyAndValue<C> {
22+
fn same_context_key_or_insert(
23+
&mut self,
24+
context_key: &'static ContextKey<C>,
25+
into_value: impl IntoContextValue<ContextValue = C::Value>,
26+
) {
27+
if self.context_key.is_same_as(context_key) {
28+
C::update_swap_value_lazily(&mut self.value, into_value);
29+
} else {
30+
self.context_key = context_key;
31+
self.value = C::make_swap_value(into_value.into_context_value());
32+
}
33+
}
34+
35+
fn provide<R>(&mut self, f: impl FnOnce() -> R) -> R {
36+
self.context_key.provide_value(&mut self.value, f)
37+
}
38+
}
39+
40+
// region: kind
41+
42+
enum Never {}
43+
pub struct Kind<C: ContextKeyInner + 'static, K>(Never, PhantomData<(C, K)>);
44+
45+
impl<C: ContextKeyInner + 'static, K: UnpinnedRenderStateKind> UnpinnedRenderStateKind
46+
for Kind<C, K>
47+
{
48+
type UnpinnedUiHandle<R: RenderHtml + ?Sized> =
49+
UiHandleWithNonReactiveState<K::UnpinnedUiHandle<R>, ContextKeyAndValue<C>>;
50+
type UnpinnedNonReactiveState<R: RenderHtml + ?Sized> = K::UnpinnedNonReactiveState<R>;
51+
type UnpinnedReactiveState = K::UnpinnedReactiveState;
52+
}
53+
54+
impl<C: ContextKeyInner, K: UnpinnedRenderStateKindPollRender> UnpinnedRenderStateKindPollRender
55+
for Kind<C, K>
56+
{
57+
fn unpinned_poll_render<R: RenderHtml + ?Sized>(
58+
//
59+
renderer: &mut R,
60+
RenderStates {
61+
ui_handle:
62+
UiHandleWithNonReactiveState {
63+
ui_handle,
64+
non_reactive_state: context_key_and_value,
65+
},
66+
non_reactive_state,
67+
reactive_state,
68+
}: experimental::UnpinnedMutRenderStatesOfKind<Self, R>,
69+
cx: &mut std::task::Context<'_>,
70+
) -> Poll<()> {
71+
context_key_and_value.provide(|| {
72+
K::unpinned_poll_render(
73+
renderer,
74+
RenderStates {
75+
ui_handle,
76+
non_reactive_state,
77+
reactive_state,
78+
},
79+
cx,
80+
)
81+
})
82+
}
83+
}
84+
85+
impl<C: ContextKeyInner + 'static, K: PinnedRenderStateKind> PinnedRenderStateKind for Kind<C, K> {
86+
type PinnedUiHandle<R: RenderHtml + ?Sized> =
87+
UiHandleWithNonReactiveState<K::PinnedUiHandle<R>, ContextKeyAndValue<C>>;
88+
type PinnedNonReactiveState<R: RenderHtml + ?Sized> = K::PinnedNonReactiveState<R>;
89+
type PinnedReactiveState = K::PinnedReactiveState;
90+
}
91+
92+
impl<C: ContextKeyInner + 'static, K: PinnedRenderStateKindPollRender>
93+
PinnedRenderStateKindPollRender for Kind<C, K>
94+
{
95+
fn pinned_poll_render<R: RenderHtml + ?Sized>(
96+
//
97+
renderer: &mut R,
98+
RenderStates {
99+
ui_handle:
100+
UiHandleWithNonReactiveState {
101+
ui_handle,
102+
non_reactive_state: context_key_and_value,
103+
},
104+
non_reactive_state,
105+
reactive_state,
106+
}: experimental::PinnedMutRenderStatesOfKind<Self, R>,
107+
cx: &mut std::task::Context<'_>,
108+
) -> Poll<()> {
109+
context_key_and_value.provide(|| {
110+
K::pinned_poll_render(
111+
renderer,
112+
RenderStates {
113+
ui_handle,
114+
non_reactive_state,
115+
reactive_state,
116+
},
117+
cx,
118+
)
119+
})
120+
}
121+
}
122+
// endregion
123+
124+
impl<T, Inner: 'static + ContextKeyInner<Value = T>, F: IntoContextValue<ContextValue = T>, FE>
125+
ElementWithContext<Inner, F, FE>
126+
{
127+
fn into_ctx_and_get_element(self) -> (ContextKeyAndValue<Inner>, FE) {
128+
let Self {
129+
context_key,
130+
into_value,
131+
get_element,
132+
} = self;
133+
let context_key_and_value = ContextKeyAndValue {
134+
context_key,
135+
value: Inner::make_swap_value(into_value.into_context_value()),
136+
};
137+
(context_key_and_value, get_element)
138+
}
139+
}
140+
141+
impl<
142+
T,
143+
Inner: 'static + ContextKeyInner<Value = T>,
144+
F: IntoContextValue<ContextValue = T>,
145+
E: CsrElement,
146+
FE: FnOnce() -> E,
147+
> CsrElement for ElementWithContext<Inner, F, FE>
148+
{
149+
type RenderStateKind = Kind<Inner, E::RenderStateKind>;
150+
151+
fn pinned_render_init<Ctx: ?Sized + frender_html::HtmlRenderContext>(
152+
//
153+
self,
154+
render_context: &mut Ctx,
155+
states: experimental::PinMutRenderInitStatesOfKind<Self::RenderStateKind, Ctx::Renderer>,
156+
) -> experimental::PinnedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind> {
157+
let (mut context_key_and_value, get_element) = self.into_ctx_and_get_element();
158+
let ui_handle = context_key_and_value
159+
.provide(|| get_element().pinned_render_init(render_context, states));
160+
161+
UiHandleWithNonReactiveState {
162+
ui_handle,
163+
non_reactive_state: context_key_and_value,
164+
}
165+
}
166+
167+
fn pinned_render_update<Ctx: ?Sized + frender_html::HtmlRenderContext>(
168+
//
169+
self,
170+
render_context: &mut Ctx,
171+
RenderStates {
172+
ui_handle:
173+
UiHandleWithNonReactiveState {
174+
ui_handle,
175+
non_reactive_state: context_key_and_value,
176+
},
177+
non_reactive_state,
178+
reactive_state,
179+
}: experimental::PinnedMutRenderStatesOfKind<Self::RenderStateKind, Ctx::Renderer>,
180+
) {
181+
let Self {
182+
context_key,
183+
into_value,
184+
get_element,
185+
} = self;
186+
context_key_and_value.same_context_key_or_insert(context_key, into_value);
187+
context_key_and_value.provide(|| {
188+
get_element().pinned_render_update(
189+
render_context,
190+
RenderStates {
191+
ui_handle,
192+
non_reactive_state,
193+
reactive_state,
194+
},
195+
);
196+
})
197+
}
198+
199+
fn unpinned_render_init<Ctx: ?Sized + frender_html::HtmlRenderContext>(
200+
//
201+
self,
202+
render_context: &mut Ctx,
203+
) -> experimental::UnpinnedRenderStatesOfKind<Self::RenderStateKind, Ctx::Renderer> {
204+
let (mut context_key_and_value, get_element) = self.into_ctx_and_get_element();
205+
206+
let RenderStates {
207+
ui_handle,
208+
non_reactive_state,
209+
reactive_state,
210+
} = context_key_and_value.provide(|| get_element().unpinned_render_init(render_context));
211+
212+
RenderStates {
213+
ui_handle: UiHandleWithNonReactiveState {
214+
ui_handle,
215+
non_reactive_state: context_key_and_value,
216+
},
217+
non_reactive_state,
218+
reactive_state,
219+
}
220+
}
221+
222+
fn unpinned_render_update<Ctx: ?Sized + frender_html::HtmlRenderContext>(
223+
//
224+
self,
225+
render_context: &mut Ctx,
226+
RenderStates {
227+
ui_handle:
228+
UiHandleWithNonReactiveState {
229+
ui_handle,
230+
non_reactive_state: context_key_and_value,
231+
},
232+
non_reactive_state,
233+
reactive_state,
234+
}: experimental::UnpinnedMutRenderStatesOfKind<
235+
Self::RenderStateKind,
236+
Ctx::Renderer,
237+
>,
238+
) {
239+
let Self {
240+
context_key,
241+
into_value,
242+
get_element,
243+
} = self;
244+
context_key_and_value.same_context_key_or_insert(context_key, into_value);
245+
246+
context_key_and_value.provide(|| {
247+
get_element().unpinned_render_update(
248+
render_context,
249+
RenderStates {
250+
ui_handle,
251+
non_reactive_state,
252+
reactive_state,
253+
},
254+
);
255+
})
256+
}
257+
}

0 commit comments

Comments
 (0)