Update signature of use_prepared_state/use_transitive_state (#3376)

* Update signature of use_prepared_state

* Update signature of use_transitive_state

* Migration guide + example

* bless trybuild tests

* please fmt

* there's one usage here as well

* use_prepared_state_with_suspension needs updates

* updated tests
This commit is contained in:
Muhammad Hamza 2023-08-19 17:58:36 +05:00 committed by GitHub
parent a27076db86
commit 42e1890f03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 162 additions and 87 deletions

View File

@ -18,7 +18,7 @@ async fn fetch_uuid() -> Uuid {
#[function_component]
fn Content() -> HtmlResult {
let uuid = use_prepared_state!(async move |_| -> Uuid { fetch_uuid().await }, ())?.unwrap();
let uuid = use_prepared_state!((), async move |_| -> Uuid { fetch_uuid().await })?.unwrap();
Ok(html! {
<div>{"Random UUID: "}{uuid}</div>

View File

@ -12,13 +12,8 @@ pub struct PreparedState {
impl Parse for PreparedState {
fn parse(input: ParseStream) -> syn::Result<Self> {
// Reads a closure.
let expr: Expr = input.parse()?;
let closure = match expr {
Expr::Closure(m) => m,
other => return Err(syn::Error::new_spanned(other, "expected closure")),
};
// Reads the deps.
let deps = input.parse()?;
input.parse::<Token![,]>().map_err(|e| {
syn::Error::new(
@ -27,6 +22,14 @@ impl Parse for PreparedState {
)
})?;
// Reads a closure.
let expr: Expr = input.parse()?;
let closure = match expr {
Expr::Closure(m) => m,
other => return Err(syn::Error::new_spanned(other, "expected closure")),
};
let return_type = match &closure.output {
ReturnType::Default => {
return Err(syn::Error::new_spanned(
@ -38,9 +41,6 @@ impl Parse for PreparedState {
ReturnType::Type(_rarrow, ty) => *ty.to_owned(),
};
// Reads the deps.
let deps = input.parse()?;
if !input.is_empty() {
let maybe_trailing_comma = input.lookahead1();
@ -107,10 +107,10 @@ impl PreparedState {
match &self.closure.asyncness {
Some(_) => quote! {
::yew::functional::use_prepared_state_with_suspension::<#rt, _, _, _>(#closure, #deps)
::yew::functional::use_prepared_state_with_suspension::<#rt, _, _, _>(#deps, #closure)
},
None => quote! {
::yew::functional::use_prepared_state::<#rt, _, _>(#closure, #deps)
::yew::functional::use_prepared_state::<#rt, _, _>(#deps, #closure)
},
}
}

View File

@ -12,13 +12,8 @@ pub struct TransitiveState {
impl Parse for TransitiveState {
fn parse(input: ParseStream) -> syn::Result<Self> {
// Reads a closure.
let expr: Expr = input.parse()?;
let closure = match expr {
Expr::Closure(m) => m,
other => return Err(syn::Error::new_spanned(other, "expected closure")),
};
// Reads the deps.
let deps = input.parse()?;
input.parse::<Token![,]>().map_err(|e| {
syn::Error::new(
@ -27,6 +22,14 @@ impl Parse for TransitiveState {
)
})?;
// Reads a closure.
let expr: Expr = input.parse()?;
let closure = match expr {
Expr::Closure(m) => m,
other => return Err(syn::Error::new_spanned(other, "expected closure")),
};
let return_type = match &closure.output {
ReturnType::Default => {
return Err(syn::Error::new_spanned(
@ -38,9 +41,6 @@ impl Parse for TransitiveState {
ReturnType::Type(_rarrow, ty) => *ty.to_owned(),
};
// Reads the deps.
let deps = input.parse()?;
if !input.is_empty() {
let maybe_trailing_comma = input.lookahead1();
@ -64,7 +64,7 @@ impl TransitiveState {
let closure = &self.closure;
quote! {
::yew::functional::use_transitive_state::<#rt, _, _>(#closure, #deps)
::yew::functional::use_transitive_state::<#rt, _, _>(#deps, #closure)
}
}

View File

@ -5,12 +5,16 @@ use yew_macro::{use_prepared_state_with_closure, use_prepared_state_without_clos
fn Comp() -> HtmlResult {
use_prepared_state_with_closure!(123)?;
use_prepared_state_with_closure!(|_| { todo!() }, 123)?;
use_prepared_state_with_closure!(123, |_| { todo!() })?;
use_prepared_state_with_closure!(|_| -> u32 { todo!() })?;
use_prepared_state_with_closure!(|_| -> u32 { todo!() }, 123)?;
use_prepared_state_with_closure!(async |_| -> u32 { todo!() })?;
use_prepared_state_with_closure!(|_| { todo!() }, 123)?;
Ok(Html::default())
}
@ -18,10 +22,14 @@ fn Comp() -> HtmlResult {
fn Comp2() -> HtmlResult {
use_prepared_state_without_closure!(123)?;
use_prepared_state_without_closure!(123, |_| { todo!() })?;
use_prepared_state_without_closure!(|_| { todo!() }, 123)?;
use_prepared_state_without_closure!(|_| -> u32 { todo!() })?;
use_prepared_state_without_closure!(|_| -> u32 { todo!() }, 123)?;
use_prepared_state_without_closure!(async |_| -> u32 { todo!() })?;
Ok(Html::default())

View File

@ -1,14 +1,16 @@
error: expected closure
--> tests/hook_macro/use_prepared_state-fail.rs:6:38
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:6:5
|
6 | use_prepared_state_with_closure!(123)?;
| ^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_prepared_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_prepared_state-fail.rs:8:38
--> tests/hook_macro/use_prepared_state-fail.rs:8:43
|
8 | use_prepared_state_with_closure!(|_| { todo!() }, 123)?;
| ^^^^^^^^^^^^^^^
8 | use_prepared_state_with_closure!(123, |_| { todo!() })?;
| ^^^^^^^^^^^^^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:10:5
@ -18,38 +20,64 @@ error: this hook takes 2 arguments but 1 argument was supplied
|
= note: this error originates in the macro `use_prepared_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:12:5
error: expected closure
--> tests/hook_macro/use_prepared_state-fail.rs:12:62
|
12 | use_prepared_state_with_closure!(async |_| -> u32 { todo!() })?;
12 | use_prepared_state_with_closure!(|_| -> u32 { todo!() }, 123)?;
| ^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:14:5
|
14 | use_prepared_state_with_closure!(async |_| -> u32 { todo!() })?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_prepared_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected closure
--> tests/hook_macro/use_prepared_state-fail.rs:19:41
--> tests/hook_macro/use_prepared_state-fail.rs:16:55
|
19 | use_prepared_state_without_closure!(123)?;
| ^^^
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_prepared_state-fail.rs:21:41
|
21 | use_prepared_state_without_closure!(|_| { todo!() }, 123)?;
| ^^^^^^^^^^^^^^^
16 | use_prepared_state_with_closure!(|_| { todo!() }, 123)?;
| ^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:23:5
|
23 | use_prepared_state_without_closure!(|_| -> u32 { todo!() })?;
23 | use_prepared_state_without_closure!(123)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_prepared_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_prepared_state-fail.rs:25:46
|
25 | use_prepared_state_without_closure!(123, |_| { todo!() })?;
| ^^^^^^^^^^^^^^^
error: expected closure
--> tests/hook_macro/use_prepared_state-fail.rs:27:58
|
27 | use_prepared_state_without_closure!(|_| { todo!() }, 123)?;
| ^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:29:5
|
29 | use_prepared_state_without_closure!(|_| -> u32 { todo!() })?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_prepared_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:25:5
error: expected closure
--> tests/hook_macro/use_prepared_state-fail.rs:31:65
|
25 | use_prepared_state_without_closure!(async |_| -> u32 { todo!() })?;
31 | use_prepared_state_without_closure!(|_| -> u32 { todo!() }, 123)?;
| ^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_prepared_state-fail.rs:33:5
|
33 | use_prepared_state_without_closure!(async |_| -> u32 { todo!() })?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_prepared_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -7,8 +7,12 @@ fn Comp() -> HtmlResult {
use_transitive_state_with_closure!(|_| { todo!() }, 123)?;
use_transitive_state_with_closure!(123, |_| { todo!() })?;
use_transitive_state_with_closure!(|_| -> u32 { todo!() })?;
use_transitive_state_with_closure!(|_| -> u32 { todo!() }, 123)?;
Ok(Html::default())
}
@ -18,8 +22,12 @@ fn Comp2() -> HtmlResult {
use_transitive_state_without_closure!(|_| { todo!() }, 123)?;
use_transitive_state_without_closure!(123, |_| { todo!() })?;
use_transitive_state_without_closure!(|_| -> u32 { todo!() })?;
use_transitive_state_without_closure!(|_| -> u32 { todo!() }, 123)?;
Ok(Html::default())
}

View File

@ -1,39 +1,67 @@
error: expected closure
--> tests/hook_macro/use_transitive_state-fail.rs:6:40
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_transitive_state-fail.rs:6:5
|
6 | use_transitive_state_with_closure!(123)?;
| ^^^
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_transitive_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_transitive_state-fail.rs:8:40
error: expected closure
--> tests/hook_macro/use_transitive_state-fail.rs:8:57
|
8 | use_transitive_state_with_closure!(|_| { todo!() }, 123)?;
| ^^^^^^^^^^^^^^^
| ^^^
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_transitive_state-fail.rs:10:45
|
10 | use_transitive_state_with_closure!(123, |_| { todo!() })?;
| ^^^^^^^^^^^^^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_transitive_state-fail.rs:10:5
--> tests/hook_macro/use_transitive_state-fail.rs:12:5
|
10 | use_transitive_state_with_closure!(|_| -> u32 { todo!() })?;
12 | use_transitive_state_with_closure!(|_| -> u32 { todo!() })?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_transitive_state_with_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected closure
--> tests/hook_macro/use_transitive_state-fail.rs:17:43
--> tests/hook_macro/use_transitive_state-fail.rs:14:64
|
17 | use_transitive_state_without_closure!(123)?;
| ^^^
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_transitive_state-fail.rs:19:43
|
19 | use_transitive_state_without_closure!(|_| { todo!() }, 123)?;
| ^^^^^^^^^^^^^^^
14 | use_transitive_state_with_closure!(|_| -> u32 { todo!() }, 123)?;
| ^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_transitive_state-fail.rs:21:5
|
21 | use_transitive_state_without_closure!(|_| -> u32 { todo!() })?;
21 | use_transitive_state_without_closure!(123)?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_transitive_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected closure
--> tests/hook_macro/use_transitive_state-fail.rs:23:60
|
23 | use_transitive_state_without_closure!(|_| { todo!() }, 123)?;
| ^^^
error: You must specify a return type for this closure. This is used when the closure is omitted from the client side rendering bundle.
--> tests/hook_macro/use_transitive_state-fail.rs:25:48
|
25 | use_transitive_state_without_closure!(123, |_| { todo!() })?;
| ^^^^^^^^^^^^^^^
error: this hook takes 2 arguments but 1 argument was supplied
--> tests/hook_macro/use_transitive_state-fail.rs:27:5
|
27 | use_transitive_state_without_closure!(|_| -> u32 { todo!() })?;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: this error originates in the macro `use_transitive_state_without_closure` (in Nightly builds, run with -Z macro-backtrace for more info)
error: expected closure
--> tests/hook_macro/use_transitive_state-fail.rs:29:67
|
29 | use_transitive_state_without_closure!(|_| -> u32 { todo!() }, 123)?;
| ^^^

View File

@ -13,8 +13,8 @@ use crate::suspense::SuspensionResult;
#[doc(hidden)]
pub fn use_prepared_state<T, D, F>(
f: F,
deps: D,
f: F,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
@ -41,7 +41,7 @@ where
fn run(self, ctx: &mut HookContext) -> Self::Output {
match ctx.creation_mode {
RenderMode::Ssr => feat_ssr::use_prepared_state(self.f, self.deps).run(ctx),
RenderMode::Ssr => feat_ssr::use_prepared_state(self.deps, self.f).run(ctx),
_ => feat_hydration::use_prepared_state(self.deps).run(ctx),
}
}
@ -52,8 +52,8 @@ where
#[doc(hidden)]
pub fn use_prepared_state_with_suspension<T, D, F, U>(
f: F,
deps: D,
f: F,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
@ -84,7 +84,7 @@ where
fn run(self, ctx: &mut HookContext) -> Self::Output {
match ctx.creation_mode {
RenderMode::Ssr => {
feat_ssr::use_prepared_state_with_suspension(self.f, self.deps).run(ctx)
feat_ssr::use_prepared_state_with_suspension(self.deps, self.f).run(ctx)
}
_ => feat_hydration::use_prepared_state(self.deps).run(ctx),
}

View File

@ -14,8 +14,8 @@ use crate::suspense::{Suspension, SuspensionResult};
#[doc(hidden)]
pub fn use_prepared_state<T, D, F>(
f: F,
deps: D,
f: F,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
@ -69,8 +69,8 @@ where
#[doc(hidden)]
pub fn use_prepared_state_with_suspension<T, D, F, U>(
f: F,
deps: D,
f: F,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,

View File

@ -39,7 +39,7 @@ pub use feat_ssr::*;
/// use yew::suspense::SuspensionResult;
///
/// #[hook]
/// pub fn use_prepared_state<T, D, F>(f: F, deps: D) -> SuspensionResult<Option<Rc<T>>>
/// pub fn use_prepared_state<T, D, F>(deps: D, f: F) -> SuspensionResult<Option<Rc<T>>>
/// where
/// D: Serialize + DeserializeOwned + PartialEq + 'static,
/// T: Serialize + DeserializeOwned + 'static,
@ -63,8 +63,8 @@ pub use feat_ssr::*;
///
/// #[hook]
/// pub fn use_prepared_state<T, D, F, U>(
/// f: F,
/// deps: D,
/// f: F,
/// ) -> SuspensionResult<Option<Rc<T>>>
/// where
/// D: Serialize + DeserializeOwned + PartialEq + 'static,

View File

@ -12,8 +12,8 @@ use crate::suspense::SuspensionResult;
#[doc(hidden)]
pub fn use_transitive_state<T, D, F>(
f: F,
deps: D,
f: F,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,
@ -40,7 +40,7 @@ where
fn run(self, ctx: &mut HookContext) -> Self::Output {
match ctx.creation_mode {
RenderMode::Ssr => feat_ssr::use_transitive_state(self.f, self.deps).run(ctx),
RenderMode::Ssr => feat_ssr::use_transitive_state(self.deps, self.f).run(ctx),
_ => feat_hydration::use_transitive_state(self.deps).run(ctx),
}
}

View File

@ -39,8 +39,8 @@ where
#[doc(hidden)]
pub fn use_transitive_state<T, D, F>(
f: F,
deps: D,
f: F,
) -> impl Hook<Output = SuspensionResult<Option<Rc<T>>>>
where
D: Serialize + DeserializeOwned + PartialEq + 'static,

View File

@ -27,7 +27,7 @@ pub use feat_ssr::*;
/// During hydration, it will only return `Ok(Some(Rc<T>))` if the component is hydrated from a
/// server-side rendering artifact and its dependency value matches.
///
/// `let state = use_transitive_state!(|deps| -> ReturnType { ... }, deps);`
/// `let state = use_transitive_state!(deps, |deps| -> ReturnType { ... });`
///
/// It has the following function signature:
///
@ -39,7 +39,7 @@ pub use feat_ssr::*;
/// use yew::suspense::SuspensionResult;
///
/// #[hook]
/// pub fn use_transitive_state<T, D, F>(f: F, deps: D) -> SuspensionResult<Option<Rc<T>>>
/// pub fn use_transitive_state<T, D, F>(deps: D, f: F) -> SuspensionResult<Option<Rc<T>>>
/// where
/// D: Serialize + DeserializeOwned + PartialEq + 'static,
/// T: Serialize + DeserializeOwned + 'static,

View File

@ -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 })?.unwrap_or_default();
Ok(html! {
<div>
@ -68,7 +68,7 @@ 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 })?.unwrap_or_default();
Ok(html! {
<div>

View File

@ -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 })?.unwrap_or_default();
Ok(html! {
<div>

View File

@ -140,12 +140,9 @@ async fn bench_concurrent_task() -> Duration {
#[function_component]
fn Comp() -> HtmlResult {
let _state = use_prepared_state!(
async move |_| -> () {
sleep(Duration::from_secs(1)).await;
},
()
)?;
let _state = use_prepared_state!((), async move |_| -> () {
sleep(Duration::from_secs(1)).await;
})?;
Ok(Html::default())
}

View File

@ -27,6 +27,12 @@ sg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDE
sg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i
sg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i
sg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i
sg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i
sg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i
sg --pattern 'use_prepared_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_prepared_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i
```
### Reasoning