Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prepared States dependency should be Reference Counted #2769

Merged
merged 9 commits into from Jul 19, 2022
7 changes: 6 additions & 1 deletion packages/yew-macro/src/use_prepared_state.rs
Expand Up @@ -61,14 +61,19 @@ impl PreparedState {
// Async closure is not stable, so we rewrite it to closure + async block
#[cfg(not(feature = "nightly"))]
pub fn rewrite_to_closure_with_async_block(&self) -> ExprClosure {
use proc_macro2::Span;
use syn::parse_quote;

let async_token = match &self.closure.asyncness {
Some(m) => m,
None => return self.closure.clone(),
};

let move_token = &self.closure.capture;
// The async block always need to be move so input can be moved into it.
let move_token = self
.closure
.capture
.unwrap_or_else(|| Token![move](Span::call_site()));
let body = &self.closure.body;

let inner = parse_quote! {
Expand Down
Expand Up @@ -40,7 +40,7 @@ async fn decode_base64(_s: &str) -> Result<Vec<u8>, JsValue> {
}

#[doc(hidden)]
pub fn use_prepared_state<T, D>(deps: D) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
pub fn use_prepared_state<T, D>(deps: Rc<D>) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
Expand All @@ -51,7 +51,7 @@ where
T: Serialize + DeserializeOwned + 'static,
{
_marker: PhantomData<T>,
deps: D,
deps: Rc<D>,
}

impl<T, D> Hook for HookProvider<T, D>
Expand Down
Expand Up @@ -14,28 +14,28 @@ use crate::suspense::SuspensionResult;
#[doc(hidden)]
pub fn use_prepared_state<T, D, F>(
f: F,
deps: D,
deps: Rc<D>,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> T,
F: FnOnce(Rc<D>) -> T,
{
struct HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> T,
F: FnOnce(Rc<D>) -> T,
{
deps: D,
deps: Rc<D>,
f: F,
}

impl<T, D, F> Hook for HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> T,
F: FnOnce(Rc<D>) -> T,
{
type Output = SuspensionResult<Option<Rc<T>>>;

Expand All @@ -53,30 +53,30 @@ where
#[doc(hidden)]
pub fn use_prepared_state_with_suspension<T, D, F, U>(
f: F,
deps: D,
deps: Rc<D>,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> U,
F: FnOnce(Rc<D>) -> U,
U: 'static + Future<Output = T>,
{
struct HookProvider<T, D, F, U>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> U,
F: FnOnce(Rc<D>) -> U,
U: 'static + Future<Output = T>,
{
deps: D,
deps: Rc<D>,
f: F,
}

impl<T, D, F, U> Hook for HookProvider<T, D, F, U>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> U,
F: FnOnce(Rc<D>) -> U,
U: 'static + Future<Output = T>,
{
type Output = SuspensionResult<Option<Rc<T>>>;
Expand Down
Expand Up @@ -10,7 +10,7 @@ use crate::suspense::SuspensionResult;

#[doc(hidden)]
#[hook]
pub fn use_prepared_state<T, D>(_deps: D) -> SuspensionResult<Option<Rc<T>>>
pub fn use_prepared_state<T, D>(_deps: Rc<D>) -> SuspensionResult<Option<Rc<T>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
Expand All @@ -20,7 +20,7 @@ where

#[doc(hidden)]
#[hook]
pub fn use_prepared_state_with_suspension<T, D>(_deps: D) -> SuspensionResult<Option<Rc<T>>>
pub fn use_prepared_state_with_suspension<T, D>(_deps: Rc<D>) -> SuspensionResult<Option<Rc<T>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
Expand Down
30 changes: 14 additions & 16 deletions packages/yew/src/functional/hooks/use_prepared_state/feat_ssr.rs
Expand Up @@ -15,38 +15,37 @@ use crate::suspense::{Suspension, SuspensionResult};
#[doc(hidden)]
pub fn use_prepared_state<T, D, F>(
f: F,
deps: D,
deps: Rc<D>,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> T,
F: FnOnce(Rc<D>) -> T,
{
struct HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> T,
F: FnOnce(Rc<D>) -> T,
{
deps: D,
deps: Rc<D>,
f: F,
}

impl<T, D, F> Hook for HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> T,
F: FnOnce(Rc<D>) -> T,
{
type Output = SuspensionResult<Option<Rc<T>>>;

fn run(self, ctx: &mut HookContext) -> Self::Output {
let f = self.f;
let deps = Rc::new(self.deps);
let Self { f, deps } = self;

let state = {
let deps = deps.clone();
use_memo(move |_| f(&deps), ()).run(ctx)
use_memo(move |_| f(deps), ()).run(ctx)
};

let state = PreparedStateBase {
Expand All @@ -70,37 +69,36 @@ where
#[doc(hidden)]
pub fn use_prepared_state_with_suspension<T, D, F, U>(
f: F,
deps: D,
deps: Rc<D>,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> U,
F: FnOnce(Rc<D>) -> U,
U: 'static + Future<Output = T>,
{
struct HookProvider<T, D, F, U>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> U,
F: FnOnce(Rc<D>) -> U,
U: 'static + Future<Output = T>,
{
deps: D,
deps: Rc<D>,
f: F,
}

impl<T, D, F, U> Hook for HookProvider<T, D, F, U>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: FnOnce(&D) -> U,
F: FnOnce(Rc<D>) -> U,
U: 'static + Future<Output = T>,
{
type Output = SuspensionResult<Option<Rc<T>>>;

fn run(self, ctx: &mut HookContext) -> Self::Output {
let f = self.f;
let deps = Rc::new(self.deps);
let Self { f, deps } = self;

let result = use_state(|| {
let (s, handle) = Suspension::new();
Expand All @@ -112,7 +110,7 @@ where
let deps = deps.clone();
let result = result.clone();
use_state(move || {
let state_f = f(&deps);
let state_f = f(deps.clone());

spawn_local(async move {
let state = state_f.await;
Expand Down
4 changes: 2 additions & 2 deletions packages/yew/src/functional/hooks/use_prepared_state/mod.rs
Expand Up @@ -43,7 +43,7 @@ pub use feat_ssr::*;
/// where
/// D: Serialize + DeserializeOwned + PartialEq + 'static,
/// T: Serialize + DeserializeOwned + 'static,
/// F: FnOnce(&D) -> T,
/// F: FnOnce(Rc<D>) -> T,
/// # { todo!() }
/// ```
///
Expand All @@ -69,7 +69,7 @@ pub use feat_ssr::*;
/// where
/// D: Serialize + DeserializeOwned + PartialEq + 'static,
/// T: Serialize + DeserializeOwned + 'static,
/// F: FnOnce(&D) -> U,
/// F: FnOnce(Rc<D>) -> U,
/// U: 'static + Future<Output = T>,
/// # { todo!() }
/// ```
Expand Down
Expand Up @@ -13,28 +13,28 @@ use crate::suspense::SuspensionResult;
#[doc(hidden)]
pub fn use_transitive_state<T, D, F>(
f: F,
deps: D,
deps: Rc<D>,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
struct HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
deps: D,
deps: Rc<D>,
f: F,
}

impl<T, D, F> Hook for HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
type Output = SuspensionResult<Option<Rc<T>>>;

Expand Down
26 changes: 13 additions & 13 deletions packages/yew/src/functional/hooks/use_transitive_state/feat_ssr.rs
Expand Up @@ -14,24 +14,24 @@ pub(super) struct TransitiveStateBase<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
pub state_fn: RefCell<Option<F>>,
pub deps: D,
pub deps: Rc<D>,
}

impl<T, D, F> PreparedState for TransitiveStateBase<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
fn prepare(&self) -> String {
let f = self.state_fn.borrow_mut().take().unwrap();
let state = f(&self.deps);
let state = f(self.deps.clone());

let state =
bincode::serialize(&(Some(&state), Some(&self.deps))).expect("failed to prepare state");
let state = bincode::serialize(&(Some(&state), Some(&*self.deps)))
.expect("failed to prepare state");

Base64::encode_string(&state)
}
Expand All @@ -40,38 +40,38 @@ where
#[doc(hidden)]
pub fn use_transitive_state<T, D, F>(
f: F,
deps: D,
deps: Rc<D>,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
struct HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
deps: D,
deps: Rc<D>,
f: F,
}

impl<T, D, F> Hook for HookProvider<T, D, F>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
T: Serialize + DeserializeOwned + 'static,
F: 'static + FnOnce(&D) -> T,
F: 'static + FnOnce(Rc<D>) -> T,
{
type Output = SuspensionResult<Option<Rc<T>>>;

fn run(self, ctx: &mut HookContext) -> Self::Output {
let f = self.f;
let Self { f, deps } = self;

ctx.next_prepared_state(move |_re_render, _| -> TransitiveStateBase<T, D, F> {
TransitiveStateBase {
state_fn: Some(f).into(),
deps: self.deps,
deps,
}
});

Expand Down
Expand Up @@ -43,7 +43,7 @@ pub use feat_ssr::*;
/// where
/// D: Serialize + DeserializeOwned + PartialEq + 'static,
/// T: Serialize + DeserializeOwned + 'static,
/// F: 'static + FnOnce(&D) -> T,
/// F: 'static + FnOnce(Rc<D>) -> T,
/// # { todo!() }
/// ```
///
Expand Down
5 changes: 3 additions & 2 deletions packages/yew/tests/use_prepared_state.rs
Expand Up @@ -18,7 +18,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
async fn use_prepared_state_works() {
#[function_component]
fn Comp() -> HtmlResult {
let ctr = use_prepared_state!(|_| -> u32 { 12345 }, ())?.unwrap_or_default();
let ctr = use_prepared_state!(|_| -> u32 { 12345 }, Rc::new(()))?.unwrap_or_default();

Ok(html! {
<div>
Expand Down Expand Up @@ -68,7 +68,8 @@ async fn use_prepared_state_works() {
async fn use_prepared_state_with_suspension_works() {
#[function_component]
fn Comp() -> HtmlResult {
let ctr = use_prepared_state!(async move |_| -> u32 { 12345 }, ())?.unwrap_or_default();
let ctr =
use_prepared_state!(async move |_| -> u32 { 12345 }, Rc::new(()))?.unwrap_or_default();

Ok(html! {
<div>
Expand Down
2 changes: 1 addition & 1 deletion packages/yew/tests/use_transitive_state.rs
Expand Up @@ -17,7 +17,7 @@ wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
async fn use_transitive_state_works() {
#[function_component]
fn Comp() -> HtmlResult {
let ctr = use_transitive_state!(|_| -> u32 { 12345 }, ())?.unwrap_or_default();
let ctr = use_transitive_state!(|_| -> u32 { 12345 }, Rc::new(()))?.unwrap_or_default();

Ok(html! {
<div>
Expand Down