Skip to content

Commit

Permalink
Merge branch 'master' into local-runtime
Browse files Browse the repository at this point in the history
  • Loading branch information
futursolo committed Aug 17, 2022
2 parents 1d7ea13 + 72213ee commit e117d3f
Show file tree
Hide file tree
Showing 41 changed files with 4,792 additions and 4,877 deletions.
14 changes: 12 additions & 2 deletions .github/workflows/main-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
uses: actions-rs/cargo@v1
with:
command: clippy
args: --all-targets --features "csr,ssr,hydration,tokio" --profile ${{ matrix.profile }} -- -D warnings
args: --all-targets --all-features --profile ${{ matrix.profile }} -- -D warnings

- name: Lint feature soundness
if: matrix.profile == 'dev'
Expand Down Expand Up @@ -181,15 +181,23 @@ jobs:

- name: Run native tests
uses: actions-rs/cargo@v1
env:
# workaround for lack of ternary operator
# see https://github.com/orgs/community/discussions/25725
RUSTFLAGS: ${{ matrix.toolchain == 'nightly' && '--cfg nightly_yew' || '' }}
with:
command: test
args: --all-targets --workspace --exclude yew

- name: Run native tests for yew
uses: actions-rs/cargo@v1
env:
# workaround for lack of ternary operator
# see https://github.com/orgs/community/discussions/25725
RUSTFLAGS: ${{ matrix.toolchain == 'nightly' && '--cfg nightly_yew' || '' }}
with:
command: test
args: -p yew --features "csr,ssr,hydration,tokio"
args: -p yew --all-features

test-lints:
name: Test lints on nightly
Expand All @@ -207,6 +215,8 @@ jobs:

- name: Run tests
uses: actions-rs/cargo@v1
env:
RUSTFLAGS: --cfg nightly_yew
with:
command: test
args: -p yew-macro test_html_lints --features lints
1 change: 1 addition & 0 deletions .github/workflows/size-cmp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ jobs:
working-directory: current-pr/examples
env:
RUSTUP_TOOLCHAIN: nightly
RUSTFLAGS: --cfg nightly_yew

- name: Collect size information
run: python3 current-pr/ci/collect_sizes.py
Expand Down
3 changes: 2 additions & 1 deletion ci/build-examples.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ for path in examples/*; do
# shellcheck disable=SC2164
cd "$path"
dist_dir="$output/$example"
export RUSTFLAGS="--cfg nightly_yew"
if [[ "$example" == "boids" || "$example" == "password_strength" ]]; then
# works around issue rust-lang/rust#96486
# where the compiler forgets to link some symbols connected to const_eval
# only an issue on nightly and with build-std enabled which we do for code size
# this deoptimizes only the examples that otherwise fail to build
export RUSTFLAGS="-Zshare-generics=n -Clto=thin"
export RUSTFLAGS="-Zshare-generics=n -Clto=thin $RUSTFLAGS"
fi

trunk build --release --dist "$dist_dir" --public-url "$PUBLIC_URL_PREFIX$example"
Expand Down
10 changes: 5 additions & 5 deletions examples/counter_functional/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ fn App() -> Html {
Callback::from(move |_| state.set(*state - 1))
};

html!(
html! {
<>
<p> {"current count: "} {*state} </p>
<button onclick={incr_counter}> {"+"} </button>
<button onclick={decr_counter}> {"-"} </button>
<p> {"current count: "} {*state} </p>
<button onclick={incr_counter}> {"+"} </button>
<button onclick={decr_counter}> {"-"} </button>
</>
)
}
}

fn main() {
Expand Down
1 change: 0 additions & 1 deletion packages/yew-macro/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,3 @@ yew = { path = "../yew" }

[features]
lints = []
nightly = []
118 changes: 78 additions & 40 deletions packages/yew-macro/src/html_tree/html_element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use syn::spanned::Spanned;
use syn::{Block, Expr, Ident, Lit, LitStr, Token};

use super::{HtmlChildrenTree, HtmlDashedName, TagTokens};
use crate::props::{ClassesForm, ElementProps, Prop};
use crate::props::{ClassesForm, ElementProps, Prop, PropDirective};
use crate::stringify::{Stringify, Value};
use crate::{non_capitalized_ascii, Peek, PeekValue};

Expand Down Expand Up @@ -135,39 +135,58 @@ impl ToTokens for HtmlElement {
// other attributes

let attributes = {
let normal_attrs = attributes.iter().map(|Prop { label, value, .. }| {
(label.to_lit_str(), value.optimize_literals_tagged())
});
let boolean_attrs = booleans.iter().filter_map(|Prop { label, value, .. }| {
let key = label.to_lit_str();
Some((
key.clone(),
match value {
Expr::Lit(e) => match &e.lit {
Lit::Bool(b) => Value::Static(if b.value {
quote! { #key }
} else {
return None;
}),
_ => Value::Dynamic(quote_spanned! {value.span()=> {
::yew::utils::__ensure_type::<::std::primitive::bool>(#value);
#key
}}),
},
expr => Value::Dynamic(
quote_spanned! {expr.span().resolved_at(Span::call_site())=>
if #expr {
::std::option::Option::Some(
::yew::virtual_dom::AttrValue::Static(#key)
)
let normal_attrs = attributes.iter().map(
|Prop {
label,
value,
directive,
..
}| {
(
label.to_lit_str(),
value.optimize_literals_tagged(),
*directive,
)
},
);
let boolean_attrs = booleans.iter().filter_map(
|Prop {
label,
value,
directive,
..
}| {
let key = label.to_lit_str();
Some((
key.clone(),
match value {
Expr::Lit(e) => match &e.lit {
Lit::Bool(b) => Value::Static(if b.value {
quote! { #key }
} else {
::std::option::Option::None
}
return None;
}),
_ => Value::Dynamic(quote_spanned! {value.span()=> {
::yew::utils::__ensure_type::<::std::primitive::bool>(#value);
#key
}}),
},
),
},
))
});
expr => Value::Dynamic(
quote_spanned! {expr.span().resolved_at(Span::call_site())=>
if #expr {
::std::option::Option::Some(
::yew::virtual_dom::AttrValue::Static(#key)
)
} else {
::std::option::Option::None
}
},
),
},
*directive,
))
},
);
let class_attr = classes.as_ref().and_then(|classes| match classes {
ClassesForm::Tuple(classes) => {
let span = classes.span();
Expand Down Expand Up @@ -196,6 +215,7 @@ impl ToTokens for HtmlElement {
__yew_classes
}
}),
None,
))
}
ClassesForm::Single(classes) => {
Expand All @@ -207,6 +227,7 @@ impl ToTokens for HtmlElement {
Some((
LitStr::new("class", lit.span()),
Value::Static(quote! { #lit }),
None,
))
}
}
Expand All @@ -216,21 +237,34 @@ impl ToTokens for HtmlElement {
Value::Dynamic(quote! {
::std::convert::Into::<::yew::html::Classes>::into(#classes)
}),
None,
))
}
}
}
});

fn apply_as(directive: Option<&PropDirective>) -> TokenStream {
match directive {
Some(PropDirective::ApplyAsProperty(token)) => {
quote_spanned!(token.span()=> ::yew::virtual_dom::ApplyAttributeAs::Property)
}
None => quote!(::yew::virtual_dom::ApplyAttributeAs::Attribute),
}
}

/// Try to turn attribute list into a `::yew::virtual_dom::Attributes::Static`
fn try_into_static(src: &[(LitStr, Value)]) -> Option<TokenStream> {
fn try_into_static(
src: &[(LitStr, Value, Option<PropDirective>)],
) -> Option<TokenStream> {
let mut kv = Vec::with_capacity(src.len());
for (k, v) in src.iter() {
for (k, v, directive) in src.iter() {
let v = match v {
Value::Static(v) => quote! { #v },
Value::Dynamic(_) => return None,
};
kv.push(quote! { [ #k, #v ] });
let apply_as = apply_as(directive.as_ref());
kv.push(quote! { ( #k, #v, #apply_as ) });
}

Some(quote! { ::yew::virtual_dom::Attributes::Static(&[#(#kv),*]) })
Expand All @@ -239,10 +273,14 @@ impl ToTokens for HtmlElement {
let attrs = normal_attrs
.chain(boolean_attrs)
.chain(class_attr)
.collect::<Vec<(LitStr, Value)>>();
.collect::<Vec<(LitStr, Value, Option<PropDirective>)>>();
try_into_static(&attrs).unwrap_or_else(|| {
let keys = attrs.iter().map(|(k, _)| quote! { #k });
let values = attrs.iter().map(|(_, v)| wrap_attr_value(v));
let keys = attrs.iter().map(|(k, ..)| quote! { #k });
let values = attrs.iter().map(|(_, v, directive)| {
let apply_as = apply_as(directive.as_ref());
let value = wrap_attr_value(v);
quote! { ::std::option::Option::map(#value, |it| (it, #apply_as)) }
});
quote! {
::yew::virtual_dom::Attributes::Dynamic{
keys: &[#(#keys),*],
Expand Down Expand Up @@ -360,7 +398,7 @@ impl ToTokens for HtmlElement {
}}
});

#[cfg(feature = "nightly")]
#[cfg(nightly_yew)]
let invalid_void_tag_msg_start = {
let span = vtag.span().unwrap();
let source_file = span.source_file().path();
Expand All @@ -369,7 +407,7 @@ impl ToTokens for HtmlElement {
format!("[{}:{}:{}] ", source_file, start.line, start.column)
};

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

// this way we get a nice error message (with the correct span) when the expression
Expand Down
2 changes: 1 addition & 1 deletion packages/yew-macro/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#![cfg_attr(feature = "nightly", feature(proc_macro_span))]
#![cfg_attr(nightly_yew, 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
Expand Down
47 changes: 37 additions & 10 deletions packages/yew-macro/src/props/prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,27 @@ use super::CHILDREN_LABEL;
use crate::html_tree::HtmlDashedName;
use crate::stringify::Stringify;

#[derive(Copy, Clone)]
pub enum PropDirective {
ApplyAsProperty(Token![~]),
}

pub struct Prop {
pub directive: Option<PropDirective>,
pub label: HtmlDashedName,
/// Punctuation between `label` and `value`.
pub value: Expr,
}
impl Parse for Prop {
fn parse(input: ParseStream) -> syn::Result<Self> {
let directive = input
.parse::<Token![~]>()
.map(PropDirective::ApplyAsProperty)
.ok();
if input.peek(Brace) {
Self::parse_shorthand_prop_assignment(input)
Self::parse_shorthand_prop_assignment(input, directive)
} else {
Self::parse_prop_assignment(input)
Self::parse_prop_assignment(input, directive)
}
}
}
Expand All @@ -33,7 +43,10 @@ impl Prop {
/// Parse a prop using the shorthand syntax `{value}`, short for `value={value}`
/// This only allows for labels with no hyphens, as it would otherwise create
/// an ambiguity in the syntax
fn parse_shorthand_prop_assignment(input: ParseStream) -> syn::Result<Self> {
fn parse_shorthand_prop_assignment(
input: ParseStream,
directive: Option<PropDirective>,
) -> syn::Result<Self> {
let value;
let _brace = braced!(value in input);
let expr = value.parse::<Expr>()?;
Expand All @@ -44,7 +57,7 @@ impl Prop {
}) = expr
{
if let (Some(ident), true) = (path.get_ident(), attrs.is_empty()) {
syn::Result::Ok(HtmlDashedName::from(ident.clone()))
Ok(HtmlDashedName::from(ident.clone()))
} else {
Err(syn::Error::new_spanned(
path,
Expand All @@ -59,11 +72,18 @@ impl Prop {
));
}?;

Ok(Self { label, value: expr })
Ok(Self {
label,
value: expr,
directive,
})
}

/// Parse a prop of the form `label={value}`
fn parse_prop_assignment(input: ParseStream) -> syn::Result<Self> {
fn parse_prop_assignment(
input: ParseStream,
directive: Option<PropDirective>,
) -> syn::Result<Self> {
let label = input.parse::<HtmlDashedName>()?;
let equals = input.parse::<Token![=]>().map_err(|_| {
syn::Error::new_spanned(
Expand All @@ -83,7 +103,11 @@ impl Prop {
}

let value = parse_prop_value(input)?;
Ok(Self { label, value })
Ok(Self {
label,
value,
directive,
})
}
}

Expand All @@ -105,10 +129,13 @@ fn parse_prop_value(input: &ParseBuffer) -> syn::Result<Expr> {

match &expr {
Expr::Lit(_) => Ok(expr),
_ => Err(syn::Error::new_spanned(
ref exp => Err(syn::Error::new_spanned(
&expr,
"the property value must be either a literal or enclosed in braces. Consider \
adding braces around your expression.",
format!(
"the property value must be either a literal or enclosed in braces. Consider \
adding braces around your expression.: {:#?}",
exp
),
)),
}
}
Expand Down
6 changes: 5 additions & 1 deletion packages/yew-macro/src/props/prop_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,11 @@ impl Parse for PropValue {
impl From<PropValue> for Prop {
fn from(prop_value: PropValue) -> Prop {
let PropValue { label, value } = prop_value;
Prop { label, value }
Prop {
label,
value,
directive: None,
}
}
}

Expand Down

0 comments on commit e117d3f

Please sign in to comment.