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

Nightly features #2743

Merged
merged 10 commits into from Jun 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 4 additions & 4 deletions .github/workflows/main-checks.yml
Expand Up @@ -25,15 +25,15 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets --all-features -- -D warnings
args: --all-targets --features "csr,ssr,hydration" -- -D warnings

- name: Lint feature soundness
run: |
cargo clippy -- --deny=warnings
cargo clippy --features=ssr -- --deny=warnings
cargo clippy --features=csr -- --deny=warnings
cargo clippy --features=hydration -- --deny=warnings
cargo clippy --all-features --all-targets -- --deny=warnings
cargo clippy --features "csr,ssr,hydration,tokio" --all-targets -- --deny=warnings
working-directory: packages/yew


Expand All @@ -55,15 +55,15 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets --all-features --release -- -D warnings
args: --all-targets --features "csr,ssr,hydration" --release -- -D warnings

- name: Lint feature soundness
run: |
cargo clippy --release -- --deny=warnings
cargo clippy --release --features=ssr -- --deny=warnings
cargo clippy --release --features=csr -- --deny=warnings
cargo clippy --release --features=hydration -- --deny=warnings
cargo clippy --release --all-features --all-targets -- --deny=warnings
cargo clippy --release --features "csr,ssr,hydration,tokio" --all-targets -- --deny=warnings
working-directory: packages/yew

spell_check:
Expand Down
2 changes: 1 addition & 1 deletion examples/simple_ssr/src/lib.rs
Expand Up @@ -18,7 +18,7 @@ async fn fetch_uuid() -> Uuid {

#[function_component]
fn Content() -> HtmlResult {
let uuid = use_prepared_state!(async |_| -> Uuid { fetch_uuid().await }, ())?.unwrap();
let uuid = use_prepared_state!(async move |_| -> Uuid { fetch_uuid().await }, ())?.unwrap();

Ok(html! {
<div>{"Random UUID: "}{uuid}</div>
Expand Down
1 change: 1 addition & 0 deletions packages/yew-macro/Cargo.toml
Expand Up @@ -35,3 +35,4 @@ yew = { path = "../yew" }

[features]
lints = []
nightly = []
18 changes: 13 additions & 5 deletions packages/yew-macro/src/html_tree/html_element.rs
Expand Up @@ -387,6 +387,18 @@ impl ToTokens for HtmlElement {
}}
});

#[cfg(feature = "nightly")]
let invalid_void_tag_msg_start = {
let span = vtag.span().unwrap();
let source_file = span.source_file().path();
let source_file = source_file.display();
let start = span.start();
format!("[{}:{}:{}] ", source_file, start.line, start.column)
};

#[cfg(not(feature = "nightly"))]
let invalid_void_tag_msg_start = "";

// this way we get a nice error message (with the correct span) when the expression
// doesn't return a valid value
quote_spanned! {expr.span()=> {
Expand Down Expand Up @@ -442,18 +454,14 @@ impl ToTokens for HtmlElement {
// These are the runtime-checks exclusive to dynamic tags.
// For literal tags this is already done at compile-time.
//
// When Span::source_file Span::start get stabilised or yew-macro introduces a
// nightly feature flag we should expand the panic message to contain the exact
// location of the dynamic tag.
//
// check void element
if !#vtag.children().is_empty() {
::std::debug_assert!(
!::std::matches!(#vtag.tag().to_ascii_lowercase().as_str(),
"area" | "base" | "br" | "col" | "embed" | "hr" | "img" | "input"
| "link" | "meta" | "param" | "source" | "track" | "wbr"
),
"a dynamic tag tried to create a `<{0}>` tag with children. `<{0}>` is a void element which can't have any children.",
concat!(#invalid_void_tag_msg_start, "a dynamic tag tried to create a `<{0}>` tag with children. `<{0}>` is a void element which can't have any children."),
#vtag.tag(),
);
}
Expand Down
2 changes: 2 additions & 0 deletions packages/yew-macro/src/lib.rs
@@ -1,3 +1,5 @@
#![cfg_attr(feature = "nightly", feature(proc_macro_span))]

//! This crate provides Yew's procedural macro `html!` which allows using JSX-like syntax
//! for generating html and the `Properties` derive macro for deriving the `Properties` trait
//! for components.
Expand Down
12 changes: 10 additions & 2 deletions packages/yew-macro/src/use_prepared_state.rs
@@ -1,7 +1,7 @@
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{parse_quote, Expr, ExprClosure, ReturnType, Token, Type};
use syn::{Expr, ExprClosure, ReturnType, Token, Type};

#[derive(Debug)]
pub struct PreparedState {
Expand Down Expand Up @@ -58,8 +58,11 @@ impl Parse for PreparedState {
}

impl PreparedState {
// Async closure is not stable, so we rewrite it to clsoure + async block
// 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 syn::parse_quote;

let async_token = match &self.closure.asyncness {
Some(m) => m,
None => return self.closure.clone(),
Expand Down Expand Up @@ -87,6 +90,11 @@ impl PreparedState {
closure
}

#[cfg(feature = "nightly")]
pub fn rewrite_to_closure_with_async_block(&self) -> ExprClosure {
self.closure.clone()
}

pub fn to_token_stream_with_closure(&self) -> TokenStream {
let deps = &self.deps;
let rt = &self.return_type;
Expand Down
1 change: 1 addition & 0 deletions packages/yew/Cargo.toml
Expand Up @@ -96,6 +96,7 @@ features = [
ssr = ["futures", "html-escape", "base64ct", "bincode"] # dep:html-escape
csr = []
hydration = ["csr", "bincode"]
nightly = ["yew-macro/nightly"]
default = []

[target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies]
Expand Down
54 changes: 42 additions & 12 deletions packages/yew/src/functional/hooks/use_force_update.rs
Expand Up @@ -6,29 +6,47 @@ use crate::functional::ReRender;
/// A handle which can be used to force a re-render of the associated
/// function component.
#[derive(Clone)]
pub struct UseForceUpdate {
pub struct UseForceUpdateHandle {
trigger: ReRender,
}

impl fmt::Debug for UseForceUpdate {
impl fmt::Debug for UseForceUpdateHandle {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("UseForceUpdate").finish()
}
}

impl UseForceUpdate {
impl UseForceUpdateHandle {
/// Trigger an unconditional re-render of the associated function component
pub fn force_update(&self) {
(self.trigger)()
}
}

// #![feature(fn_traits)] // required nightly feature to make UseForceUpdate callable directly
// impl Fn<()> for UseForceUpdate {
// extern "rust-call" fn call(&self, _args: ()) {
// self.force_update()
// }
// }
#[cfg(feature = "nightly")]
mod feat_nightly {
use super::*;

impl FnOnce<()> for UseForceUpdateHandle {
type Output = ();

extern "rust-call" fn call_once(self, _args: ()) -> Self::Output {
self.force_update()
}
}

impl FnMut<()> for UseForceUpdateHandle {
extern "rust-call" fn call_mut(&mut self, _args: ()) -> Self::Output {
self.force_update()
}
}

impl Fn<()> for UseForceUpdateHandle {
extern "rust-call" fn call(&self, _args: ()) -> Self::Output {
self.force_update()
}
}
}

/// This hook is used to manually force a function component to re-render.
///
Expand Down Expand Up @@ -78,18 +96,30 @@ impl UseForceUpdate {
///
/// [`use_state`]: super::use_state()
/// [`use_reducer`]: super::use_reducer()
pub fn use_force_update() -> impl Hook<Output = UseForceUpdate> {
pub fn use_force_update() -> impl Hook<Output = UseForceUpdateHandle> {
struct UseRerenderHook;

impl Hook for UseRerenderHook {
type Output = UseForceUpdate;
type Output = UseForceUpdateHandle;

fn run(self, ctx: &mut HookContext) -> Self::Output {
UseForceUpdate {
UseForceUpdateHandle {
trigger: ctx.re_render.clone(),
}
}
}

UseRerenderHook
}

#[cfg(all(test, feature = "nightly"))]
mod nightly_test {
use yew::prelude::*;

#[function_component]
fn ManuallyUpdatedDate() -> Html {
let trigger = use_force_update();
let _ = move || trigger();
html! {}
}
}
4 changes: 4 additions & 0 deletions packages/yew/src/lib.rs
@@ -1,6 +1,10 @@
#![allow(clippy::needless_doctest_main)]
#![doc(html_logo_url = "https://yew.rs/img/logo.png")]
#![cfg_attr(documenting, feature(doc_cfg))]
#![cfg_attr(
feature = "nightly",
feature(fn_traits, async_closure, unboxed_closures)
)]

//! # Yew Framework - API Documentation
//!
Expand Down
3 changes: 2 additions & 1 deletion packages/yew/tests/use_prepared_state.rs
@@ -1,5 +1,6 @@
#![cfg(target_arch = "wasm32")]
#![cfg(feature = "hydration")]
#![cfg_attr(feature = "nightly", feature(async_closure))]

use std::time::Duration;

Expand Down Expand Up @@ -67,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 |_| -> u32 { 12345 }, ())?.unwrap_or_default();
let ctr = use_prepared_state!(async move |_| -> u32 { 12345 }, ())?.unwrap_or_default();

Ok(html! {
<div>
Expand Down