Skip to content

Commit abbfc3f

Browse files
committed
wip: better design for CsrElement
1 parent 97e2429 commit abbfc3f

File tree

10 files changed

+289
-188
lines changed

10 files changed

+289
-188
lines changed

packages/frender-common/src/csr.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ impl StateUnmount for () {
1616
fn state_unmount(self: Pin<&mut Self>) {}
1717
}
1818

19+
impl<T: StateUnmount, const N: usize> StateUnmount for [T; N] {
20+
fn state_unmount(self: Pin<&mut Self>) {
21+
frender_pin_utils::pin_project_iter_mut_array(self).for_each(T::state_unmount)
22+
}
23+
}
24+
1925
macro_rules! impl_render_for_tuple {
2026
($($name:ident ($($field_var:ident as $field:ident),+) ,)+) => {
2127
$(

packages/frender-csr/src/lib.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ pub mod render_state;
66
mod render_state_trait;
77

88
pub mod event_listener;
9+
10+
pin_project_lite::pin_project! {
11+
struct T<'a> {
12+
#[pin]
13+
a: &'a ()
14+
}
15+
}

packages/frender-csr/src/render_state/array.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ impl<R: ?Sized, S: RenderState<R>, const N: usize> RenderState<R> for [S; N] {
4545
}
4646
}
4747

48+
// TODO: remove
4849
pub struct ArrayRenderState<S, const N: usize>(pub [S; N]);
4950

5051
impl<S, const N: usize> ArrayRenderState<S, N> {

packages/frender-html/src/element.rs

Lines changed: 54 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,59 @@
11
use std::{pin::Pin, task::Poll};
22

3+
use frender_common::reactive_value::AsOptionMut;
34
use frender_dom::{render::RenderContext, ui_handle::UiHandle, StateUnmount};
45

56
use crate::RenderHtml;
67

7-
pub trait HtmlRenderContext: RenderContext<Renderer = Self::HtmlRenderer> {
8-
type HtmlRenderer: RenderHtml + ?Sized;
9-
}
10-
11-
impl<Ctx: ?Sized + RenderContext> HtmlRenderContext for Ctx
12-
where
13-
Ctx::Renderer: RenderHtml,
14-
{
15-
type HtmlRenderer = Ctx::Renderer;
16-
}
17-
18-
// pub trait StatePollRender<U: ?Sized, R: ?Sized> {
19-
// fn state_poll_render(self: Pin<&mut Self>, ui_handle: &mut U, renderer: &mut R) -> Poll<()>;
20-
// }
21-
22-
// + StatePollRender<Self, R>
23-
/// A synonymous trait for [`StatePollRender`] with ui handle as Self.
24-
25-
// impl<UH: ?Sized, S: ?Sized + StatePollRender<Self, R>, R: ?Sized> UiHandlePollRender<S, R> for UH {
26-
// #[inline(always)]
27-
// fn ui_handle_poll_render(&mut self, state: &mut S, renderer: &mut R) -> Poll<()> {
28-
// state.state_poll_render(self, renderer)
29-
// }
30-
// }
8+
pub trait HtmlRenderContext: RenderContext<Renderer: RenderHtml> {}
9+
impl<Ctx: ?Sized + RenderContext<Renderer: RenderHtml>> HtmlRenderContext for Ctx {}
3110

3211
pub trait PinnedRenderStateKind {
3312
/// Ui handles that are renderer-specific and **NOT** pinned in pinned environment.
3413
type PinnedUiHandle<R: RenderHtml + ?Sized>: UiHandle<R>;
3514

36-
// TODO: should `*NonReactiveState` and `*ReactiveState` be merged as one `*State`?
37-
/// Renderer-specific non-reactive state in pinned environment.
38-
type PinnedNonReactiveState<R: RenderHtml + ?Sized>: Default;
39-
/// Renderer-agnostic reactive state in pinned environment.
15+
/// State in pinned environment.
4016
///
4117
/// [`Default`] is required so that the state can be constructed and then pinned before [`CsrElement::pinned_render_init`].
4218
/// Note that [`UnpinnedRenderStateKind::UnpinnedReactiveState`] requires `Default` for a different reason.
43-
type PinnedReactiveState: StateUnmount + Default;
19+
type PinnedState<R: RenderHtml + ?Sized>: StateUnmount;
20+
type PinnedStateDefault<R: RenderHtml + ?Sized>: Default + AsOptionMut<Self::PinnedState<R>> + StateUnmount;
4421
}
4522

4623
pub trait PinnedRenderStateKindPollRender: PinnedRenderStateKind {
4724
fn pinned_poll_render<R: RenderHtml + ?Sized>(
4825
//
4926
renderer: &mut R,
50-
states: PinnedMutRenderStatesOfKind<Self, R>,
27+
state: Pin<&mut Self::PinnedState<R>>,
28+
ui_handle: &mut Self::PinnedUiHandle<R>,
5129
cx: &mut std::task::Context<'_>,
5230
) -> Poll<()>;
5331
}
5432

5533
pub trait UnpinnedRenderStateKind {
5634
/// Ui handles that are renderer-specific and not pinned in unpinned environment.
5735
type UnpinnedUiHandle<R: RenderHtml + ?Sized>: UiHandle<R>;
58-
/// Renderer-specific non-reactive state in unpinned environment.
59-
type UnpinnedNonReactiveState<R: RenderHtml + ?Sized>;
60-
/// Renderer-agnostic reactive state in unpinned environment.
36+
37+
/// State in unpinned environment.
6138
///
62-
/// [`Unpin`] is required so that [`StateUnmount`] can be used
39+
/// [`Unpin`] is required so that [`StateUnmount`] can be used without defining another unpinned variant
6340
/// (caller can safely create a `Pin<&mut _>` from unpinned places
6441
/// and then call [`StateUnmount::state_unmount`]).
65-
///
66-
/// Another solution is to split trait [`StateUnmount`] into pinned and unpinned variants,
67-
/// then we don't need the `Unpin` bound.
68-
type UnpinnedReactiveState: StateUnmount + Default + Unpin;
42+
type UnpinnedState<R: RenderHtml + ?Sized>: StateUnmount + Unpin;
6943

70-
#[cfg(todo)]
7144
/// [`Default`] is required so that [`RenderStateKind`](CsrElement::RenderStateKind) of `Option<impl CsrElement>`
7245
/// don't need to wrap `UnpinnedReactiveState` with `Option`.
46+
/// This optimizes `impl CsrElement for Option<impl CsrElement<RenderStateKind: UnpinnedRenderStateKind<UnpinnedState<_>: Default>>>`.
7347
/// Note that [`PinnedRenderStateKind::PinnedReactiveState`] requires `Default` for a different reason.
74-
type UnpinnedReactiveStateDefault: StateUnmount + Default + Unpin;
48+
type UnpinnedStateDefault<R: RenderHtml + ?Sized>: Default + AsOptionMut<Self::UnpinnedState<R>> + StateUnmount + Unpin;
7549
}
7650

7751
pub trait UnpinnedRenderStateKindPollRender: UnpinnedRenderStateKind {
7852
fn unpinned_poll_render<R: RenderHtml + ?Sized>(
7953
//
8054
renderer: &mut R,
81-
states: UnpinnedMutRenderStatesOfKind<Self, R>,
55+
state: &mut Self::UnpinnedState<R>,
56+
ui_handle: &mut Self::UnpinnedUiHandle<R>,
8257
cx: &mut std::task::Context<'_>,
8358
) -> Poll<()>;
8459
}
@@ -87,74 +62,67 @@ pub trait UnpinnedRenderStateKindPollRender: UnpinnedRenderStateKind {
8762
pub trait RenderStateKind: UnpinnedRenderStateKindPollRender + PinnedRenderStateKindPollRender {}
8863
impl<K: ?Sized + UnpinnedRenderStateKindPollRender + PinnedRenderStateKindPollRender> RenderStateKind for K {}
8964

90-
pub type PinnedMutRenderStatesOfKind<'a, Kind, Renderer> = RenderStates<
91-
//
92-
&'a mut <Kind as PinnedRenderStateKind>::PinnedUiHandle<Renderer>,
93-
Pin<&'a mut <Kind as PinnedRenderStateKind>::PinnedNonReactiveState<Renderer>>,
94-
Pin<&'a mut <Kind as PinnedRenderStateKind>::PinnedReactiveState>,
95-
>;
96-
97-
pub type UnpinnedMutRenderStatesOfKind<'a, Kind, Renderer> = RenderStates<
98-
//
99-
&'a mut <Kind as UnpinnedRenderStateKind>::UnpinnedUiHandle<Renderer>,
100-
&'a mut <Kind as UnpinnedRenderStateKind>::UnpinnedNonReactiveState<Renderer>,
101-
&'a mut <Kind as UnpinnedRenderStateKind>::UnpinnedReactiveState,
102-
>;
103-
104-
pub type UnpinnedRenderStatesOfKind<Kind, Renderer> = RenderStates<
105-
//
106-
<Kind as UnpinnedRenderStateKind>::UnpinnedUiHandle<Renderer>,
107-
<Kind as UnpinnedRenderStateKind>::UnpinnedNonReactiveState<Renderer>,
108-
<Kind as UnpinnedRenderStateKind>::UnpinnedReactiveState,
109-
>;
110-
111-
pub struct RenderStates<UH, NRS, RS> {
112-
pub ui_handle: UH,
113-
pub non_reactive_state: NRS,
114-
pub reactive_state: RS,
115-
}
116-
117-
pub(crate) type PinnedMutRenderStates<'a, UH, NRS, RS> = RenderStates<&'a mut UH, Pin<&'a mut NRS>, Pin<&'a mut RS>>;
118-
pub(crate) type UnpinnedMutRenderStates<'a, UH, NRS, RS> = RenderStates<&'a mut UH, &'a mut NRS, &'a mut RS>;
119-
12065
pub type PinnedUiHandleOfKind<R, K> = <K as PinnedRenderStateKind>::PinnedUiHandle<R>;
121-
pub type UnpinnedUiHandleOfKind<R, K> = <K as UnpinnedRenderStateKind>::UnpinnedUiHandle<R>;
122-
123-
pub struct PinMutRenderInitStates<'a, NRS, RS> {
124-
pub non_reactive_state: Pin<&'a mut NRS>,
125-
pub reactive_state: Pin<&'a mut RS>,
126-
}
66+
pub type PinnedUnmountedUiHandleOfKind<R, K> = <<K as PinnedRenderStateKind>::PinnedUiHandle<R> as UiHandle<R>>::Unmounted;
67+
pub type PinnedStateOfKind<R, K> = <K as PinnedRenderStateKind>::PinnedState<R>;
68+
pub type PinnedStateDefaultOfKind<R, K> = <K as PinnedRenderStateKind>::PinnedStateDefault<R>;
12769

128-
pub type PinMutRenderInitStatesOfKind<'a, Kind, Renderer> = PinMutRenderInitStates<'a, <Kind as PinnedRenderStateKind>::PinnedNonReactiveState<Renderer>, <Kind as PinnedRenderStateKind>::PinnedReactiveState>;
70+
pub type UnpinnedUiHandleOfKind<R, K> = <K as UnpinnedRenderStateKind>::UnpinnedUiHandle<R>;
71+
pub type UnpinnedUnmountedUiHandleOfKind<R, K> = <<K as UnpinnedRenderStateKind>::UnpinnedUiHandle<R> as UiHandle<R>>::Unmounted;
72+
pub type UnpinnedStateOfKind<R, K> = <K as UnpinnedRenderStateKind>::UnpinnedState<R>;
73+
pub type UnpinnedStateDefaultOfKind<R, K> = <K as UnpinnedRenderStateKind>::UnpinnedStateDefault<R>;
12974

13075
pub trait CsrElement {
13176
type RenderStateKind: RenderStateKind;
13277

78+
/// The implementation should _initialize_ `state_default` so that [`AsOptionMut::<PinnedState>::as_option_mut(state_default).is_some()`](AsOptionMut)
79+
/// or future usage will panic.
80+
/// Caller of this method cannot consider this requirement as a safety guarantee.
13381
fn pinned_render_init<Ctx: ?Sized + HtmlRenderContext>(
13482
//
13583
self,
13684
render_context: &mut Ctx,
137-
states: PinMutRenderInitStatesOfKind<Self::RenderStateKind, Ctx::Renderer>,
85+
state_default: Pin<&mut PinnedStateDefaultOfKind<Ctx::Renderer, Self::RenderStateKind>>,
13886
) -> PinnedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind>;
13987

140-
fn pinned_render_update<Ctx: ?Sized + HtmlRenderContext>(
141-
//
88+
fn pinned_render_init_by_reusing<Ctx: ?Sized + HtmlRenderContext>(
14289
self,
14390
render_context: &mut Ctx,
144-
states: PinnedMutRenderStatesOfKind<Self::RenderStateKind, Ctx::Renderer>,
91+
reused_state: Pin<&mut PinnedStateOfKind<Ctx::Renderer, Self::RenderStateKind>>,
92+
unmounted_ui_handle: PinnedUnmountedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind>,
93+
) -> PinnedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind>;
94+
95+
fn pinned_render_update<Renderer: ?Sized + RenderHtml>(
96+
//
97+
self,
98+
renderer: &mut Renderer,
99+
state: Pin<&mut PinnedStateOfKind<Renderer, Self::RenderStateKind>>,
100+
ui_handle: &mut PinnedUiHandleOfKind<Renderer, Self::RenderStateKind>,
145101
);
146102

147103
fn unpinned_render_init<Ctx: ?Sized + HtmlRenderContext>(
148104
//
149105
self,
150106
render_context: &mut Ctx,
151-
) -> UnpinnedRenderStatesOfKind<Self::RenderStateKind, Ctx::Renderer>;
152-
153-
fn unpinned_render_update<Ctx: ?Sized + HtmlRenderContext>(
107+
) -> (
154108
//
109+
UnpinnedStateOfKind<Ctx::Renderer, Self::RenderStateKind>,
110+
UnpinnedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind>,
111+
);
112+
113+
fn unpinned_render_init_by_reusing<Ctx: ?Sized + HtmlRenderContext>(
155114
self,
156115
render_context: &mut Ctx,
157-
states: UnpinnedMutRenderStatesOfKind<Self::RenderStateKind, Ctx::Renderer>,
116+
reused_state: &mut UnpinnedStateOfKind<Ctx::Renderer, Self::RenderStateKind>,
117+
unmounted_ui_handle: UnpinnedUnmountedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind>,
118+
) -> UnpinnedUiHandleOfKind<Ctx::Renderer, Self::RenderStateKind>;
119+
120+
fn unpinned_render_update<Renderer: ?Sized + RenderHtml>(
121+
//
122+
self,
123+
renderer: &mut Renderer,
124+
state: &mut UnpinnedStateOfKind<Renderer, Self::RenderStateKind>,
125+
ui_handle: &mut UnpinnedUiHandleOfKind<Renderer, Self::RenderStateKind>,
158126
);
159127
}
160128

0 commit comments

Comments
 (0)