mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Add custom type for attribute values (#1994)
* Add custom type for attribute values * fix tests/example * Remove `PartialEq<String>` and it's usage * `ReferenceCounted` -> `Rc` * fucking fake * please CI, just turn green
This commit is contained in:
parent
3ebd866d13
commit
2f47b09da4
@ -6,7 +6,7 @@ edition = "2018"
|
|||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
fake = "2.2"
|
fake = "=2.4.1"
|
||||||
getrandom = { version = "0.2", features = ["js"] }
|
getrandom = { version = "0.2", features = ["js"] }
|
||||||
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
instant = { version = "0.1", features = ["wasm-bindgen"] }
|
||||||
log = "0.4"
|
log = "0.4"
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use crate::{content, generator::Generated, Route};
|
use crate::{content, generator::Generated, Route};
|
||||||
use content::PostPart;
|
use content::PostPart;
|
||||||
use std::borrow::Cow;
|
|
||||||
use yew::prelude::*;
|
use yew::prelude::*;
|
||||||
use yew_router::prelude::*;
|
use yew_router::prelude::*;
|
||||||
|
|
||||||
@ -39,7 +38,7 @@ impl Component for Post {
|
|||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<section class="hero is-medium is-light has-background">
|
<section class="hero is-medium is-light has-background">
|
||||||
<img class="hero-background is-transparent" src={Cow::Owned(post.meta.image_url.clone())} />
|
<img class="hero-background is-transparent" src={post.meta.image_url.clone()} />
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1 class="title">
|
<h1 class="title">
|
||||||
@ -70,7 +69,7 @@ impl Post {
|
|||||||
<article class="media block box my-6">
|
<article class="media block box my-6">
|
||||||
<figure class="media-left">
|
<figure class="media-left">
|
||||||
<p class="image is-64x64">
|
<p class="image is-64x64">
|
||||||
<img src={Cow::Owned(quote.author.image_url.clone())} loading="lazy" />
|
<img src={quote.author.image_url.clone()} loading="lazy" />
|
||||||
</p>
|
</p>
|
||||||
</figure>
|
</figure>
|
||||||
<div class="media-content">
|
<div class="media-content">
|
||||||
@ -90,7 +89,7 @@ impl Post {
|
|||||||
fn render_section_hero(&self, section: &content::Section) -> Html {
|
fn render_section_hero(&self, section: &content::Section) -> Html {
|
||||||
html! {
|
html! {
|
||||||
<section class="hero is-dark has-background mt-6 mb-3">
|
<section class="hero is-dark has-background mt-6 mb-3">
|
||||||
<img class="hero-background is-transparent" src={Cow::Owned(section.image_url.clone())} loading="lazy" />
|
<img class="hero-background is-transparent" src={section.image_url.clone()} loading="lazy" />
|
||||||
<div class="hero-body">
|
<div class="hero-body">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h2 class="subtitle">{ §ion.title }</h2>
|
<h2 class="subtitle">{ §ion.title }</h2>
|
||||||
|
|||||||
@ -168,7 +168,7 @@ impl ToTokens for HtmlElement {
|
|||||||
expr => Value::Dynamic(quote_spanned! {expr.span()=>
|
expr => Value::Dynamic(quote_spanned! {expr.span()=>
|
||||||
if #expr {
|
if #expr {
|
||||||
::std::option::Option::Some(
|
::std::option::Option::Some(
|
||||||
::std::borrow::Cow::<'static, ::std::primitive::str>::Borrowed(#key)
|
::yew::virtual_dom::AttrValue::Static(#key)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
::std::option::Option::None
|
::std::option::Option::None
|
||||||
|
|||||||
@ -6,17 +6,17 @@ use syn::{Expr, Lit, LitStr};
|
|||||||
/// Stringify a value at runtime.
|
/// Stringify a value at runtime.
|
||||||
fn stringify_at_runtime(src: impl ToTokens) -> TokenStream {
|
fn stringify_at_runtime(src: impl ToTokens) -> TokenStream {
|
||||||
quote_spanned! {src.span()=>
|
quote_spanned! {src.span()=>
|
||||||
::std::convert::Into::<::std::borrow::Cow::<'static, ::std::primitive::str>>::into(#src)
|
::std::convert::Into::<::yew::virtual_dom::AttrValue>::into(#src)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create `Cow<'static, str>` construction calls.
|
/// Create `AttrValue` construction calls.
|
||||||
///
|
///
|
||||||
/// This is deliberately not implemented for strings to preserve spans.
|
/// This is deliberately not implemented for strings to preserve spans.
|
||||||
pub trait Stringify {
|
pub trait Stringify {
|
||||||
/// Try to turn the value into a string literal.
|
/// Try to turn the value into a string literal.
|
||||||
fn try_into_lit(&self) -> Option<LitStr>;
|
fn try_into_lit(&self) -> Option<LitStr>;
|
||||||
/// Create `Cow<'static, str>` however possible.
|
/// Create `AttrValue` however possible.
|
||||||
fn stringify(&self) -> TokenStream;
|
fn stringify(&self) -> TokenStream;
|
||||||
|
|
||||||
/// Optimize literals to `&'static str`, otherwise keep the value as is.
|
/// Optimize literals to `&'static str`, otherwise keep the value as is.
|
||||||
@ -71,7 +71,7 @@ impl Stringify for LitStr {
|
|||||||
|
|
||||||
fn stringify(&self) -> TokenStream {
|
fn stringify(&self) -> TokenStream {
|
||||||
quote_spanned! {self.span()=>
|
quote_spanned! {self.span()=>
|
||||||
::std::borrow::Cow::<'static, ::std::primitive::str>::Borrowed(#self)
|
::yew::virtual_dom::AttrValue::Static(#self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -342,8 +342,8 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
|
|||||||
| ^ the trait `IntoPropValue<String>` is not implemented for `{integer}`
|
| ^ the trait `IntoPropValue<String>` is not implemented for `{integer}`
|
||||||
|
|
|
|
||||||
= help: the following implementations were found:
|
= help: the following implementations were found:
|
||||||
<&'static str as IntoPropValue<Cow<'static, str>>>
|
<&'static str as IntoPropValue<AttrValue>>
|
||||||
<&'static str as IntoPropValue<Option<Cow<'static, str>>>>
|
<&'static str as IntoPropValue<Option<AttrValue>>>
|
||||||
<&'static str as IntoPropValue<Option<String>>>
|
<&'static str as IntoPropValue<Option<String>>>
|
||||||
<&'static str as IntoPropValue<String>>
|
<&'static str as IntoPropValue<String>>
|
||||||
and 11 others
|
and 11 others
|
||||||
@ -355,8 +355,8 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
|
|||||||
| ^ the trait `IntoPropValue<String>` is not implemented for `{integer}`
|
| ^ the trait `IntoPropValue<String>` is not implemented for `{integer}`
|
||||||
|
|
|
|
||||||
= help: the following implementations were found:
|
= help: the following implementations were found:
|
||||||
<&'static str as IntoPropValue<Cow<'static, str>>>
|
<&'static str as IntoPropValue<AttrValue>>
|
||||||
<&'static str as IntoPropValue<Option<Cow<'static, str>>>>
|
<&'static str as IntoPropValue<Option<AttrValue>>>
|
||||||
<&'static str as IntoPropValue<Option<String>>>
|
<&'static str as IntoPropValue<Option<String>>>
|
||||||
<&'static str as IntoPropValue<String>>
|
<&'static str as IntoPropValue<String>>
|
||||||
and 11 others
|
and 11 others
|
||||||
|
|||||||
@ -1,209 +1,209 @@
|
|||||||
error: this opening tag has no corresponding closing tag
|
error: this opening tag has no corresponding closing tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:7:13
|
--> tests/html_macro/element-fail.rs:7:13
|
||||||
|
|
|
|
||||||
7 | html! { <div> };
|
7 | html! { <div> };
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: this opening tag has no corresponding closing tag
|
error: this opening tag has no corresponding closing tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:8:18
|
--> tests/html_macro/element-fail.rs:8:18
|
||||||
|
|
|
|
||||||
8 | html! { <div><div> };
|
8 | html! { <div><div> };
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: this opening tag has no corresponding closing tag
|
error: this opening tag has no corresponding closing tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:9:13
|
--> tests/html_macro/element-fail.rs:9:13
|
||||||
|
|
|
|
||||||
9 | html! { <div><div></div> };
|
9 | html! { <div><div></div> };
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: this closing tag has no corresponding opening tag
|
error: this closing tag has no corresponding opening tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:12:13
|
--> tests/html_macro/element-fail.rs:12:13
|
||||||
|
|
|
|
||||||
12 | html! { </div> };
|
12 | html! { </div> };
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: this closing tag has no corresponding opening tag
|
error: this closing tag has no corresponding opening tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:13:18
|
--> tests/html_macro/element-fail.rs:13:18
|
||||||
|
|
|
|
||||||
13 | html! { <div></span></div> };
|
13 | html! { <div></span></div> };
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)
|
error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:14:20
|
--> tests/html_macro/element-fail.rs:14:20
|
||||||
|
|
|
|
||||||
14 | html! { <img /></img> };
|
14 | html! { <img /></img> };
|
||||||
| ^^^^^^
|
| ^^^^^^
|
||||||
|
|
||||||
error: this closing tag has no corresponding opening tag
|
error: this closing tag has no corresponding opening tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:17:18
|
--> tests/html_macro/element-fail.rs:17:18
|
||||||
|
|
|
|
||||||
17 | html! { <div></span> };
|
17 | html! { <div></span> };
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: this closing tag has no corresponding opening tag
|
error: this closing tag has no corresponding opening tag
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:18:20
|
--> tests/html_macro/element-fail.rs:18:20
|
||||||
|
|
|
|
||||||
18 | html! { <tag-a></tag-b> };
|
18 | html! { <tag-a></tag-b> };
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)
|
error: only one root html element is allowed (hint: you can wrap multiple html elements in a fragment `<></>`)
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:21:24
|
--> tests/html_macro/element-fail.rs:21:24
|
||||||
|
|
|
|
||||||
21 | html! { <div></div><div></div> };
|
21 | html! { <div></div><div></div> };
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: expected a valid html element
|
error: expected a valid html element
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:23:18
|
--> tests/html_macro/element-fail.rs:23:18
|
||||||
|
|
|
|
||||||
23 | html! { <div>Invalid</div> };
|
23 | html! { <div>Invalid</div> };
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: `attr` can only be specified once but is given here again
|
error: `attr` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:26:27
|
--> tests/html_macro/element-fail.rs:26:27
|
||||||
|
|
|
|
||||||
26 | html! { <input attr=1 attr=2 /> };
|
26 | html! { <input attr=1 attr=2 /> };
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: `value` can only be specified once but is given here again
|
error: `value` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:27:32
|
--> tests/html_macro/element-fail.rs:27:32
|
||||||
|
|
|
|
||||||
27 | html! { <input value="123" value="456" /> };
|
27 | html! { <input value="123" value="456" /> };
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: `kind` can only be specified once but is given here again
|
error: `kind` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:28:36
|
--> tests/html_macro/element-fail.rs:28:36
|
||||||
|
|
|
|
||||||
28 | html! { <input kind="checkbox" kind="submit" /> };
|
28 | html! { <input kind="checkbox" kind="submit" /> };
|
||||||
| ^^^^
|
| ^^^^
|
||||||
|
|
||||||
error: `checked` can only be specified once but is given here again
|
error: `checked` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:29:33
|
--> tests/html_macro/element-fail.rs:29:33
|
||||||
|
|
|
|
||||||
29 | html! { <input checked=true checked=false /> };
|
29 | html! { <input checked=true checked=false /> };
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: `disabled` can only be specified once but is given here again
|
error: `disabled` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:30:34
|
--> tests/html_macro/element-fail.rs:30:34
|
||||||
|
|
|
|
||||||
30 | html! { <input disabled=true disabled=false /> };
|
30 | html! { <input disabled=true disabled=false /> };
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: `selected` can only be specified once but is given here again
|
error: `selected` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:31:35
|
--> tests/html_macro/element-fail.rs:31:35
|
||||||
|
|
|
|
||||||
31 | html! { <option selected=true selected=false /> };
|
31 | html! { <option selected=true selected=false /> };
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: `class` can only be specified once but is given here again
|
error: `class` can only be specified once but is given here again
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:32:32
|
--> tests/html_macro/element-fail.rs:32:32
|
||||||
|
|
|
|
||||||
32 | html! { <div class="first" class="second" /> };
|
32 | html! { <div class="first" class="second" /> };
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: `ref` can only be specified once
|
error: `ref` can only be specified once
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:33:20
|
--> tests/html_macro/element-fail.rs:33:20
|
||||||
|
|
|
|
||||||
33 | html! { <input ref={()} ref={()} /> };
|
33 | html! { <input ref={()} ref={()} /> };
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: `ref` can only be specified once
|
error: `ref` can only be specified once
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:63:20
|
--> tests/html_macro/element-fail.rs:63:20
|
||||||
|
|
|
|
||||||
63 | html! { <input ref={()} ref={()} /> };
|
63 | html! { <input ref={()} ref={()} /> };
|
||||||
| ^^^
|
| ^^^
|
||||||
|
|
||||||
error: the tag `<input>` is a void element and cannot have children (hint: rewrite this as `<input/>`)
|
error: the tag `<input>` is a void element and cannot have children (hint: rewrite this as `<input/>`)
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:66:13
|
--> tests/html_macro/element-fail.rs:66:13
|
||||||
|
|
|
|
||||||
66 | html! { <input type="text"></input> };
|
66 | html! { <input type="text"></input> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: the tag `<iNpUt>` is a void element and cannot have children (hint: rewrite this as `<iNpUt/>`)
|
error: the tag `<iNpUt>` is a void element and cannot have children (hint: rewrite this as `<iNpUt/>`)
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:68:13
|
--> tests/html_macro/element-fail.rs:68:13
|
||||||
|
|
|
|
||||||
68 | html! { <iNpUt type="text"></iNpUt> };
|
68 | html! { <iNpUt type="text"></iNpUt> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: this dynamic tag is missing an expression block defining its value
|
error: this dynamic tag is missing an expression block defining its value
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:71:14
|
--> tests/html_macro/element-fail.rs:71:14
|
||||||
|
|
|
|
||||||
71 | html! { <@></@> };
|
71 | html! { <@></@> };
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: this dynamic tag is missing an expression block defining its value
|
error: this dynamic tag is missing an expression block defining its value
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:72:14
|
--> tests/html_macro/element-fail.rs:72:14
|
||||||
|
|
|
|
||||||
72 | html! { <@/> };
|
72 | html! { <@/> };
|
||||||
| ^
|
| ^
|
||||||
|
|
||||||
error: dynamic closing tags must not have a body (hint: replace it with just `</@>`)
|
error: dynamic closing tags must not have a body (hint: replace it with just `</@>`)
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:75:27
|
--> tests/html_macro/element-fail.rs:75:27
|
||||||
|
|
|
|
||||||
75 | html! { <@{"test"}></@{"test"}> };
|
75 | html! { <@{"test"}></@{"test"}> };
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:83:24
|
--> tests/html_macro/element-fail.rs:83:24
|
||||||
|
|
|
|
||||||
83 | html! { <div class=("deprecated", "warning") /> };
|
83 | html! { <div class=("deprecated", "warning") /> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:84:24
|
--> tests/html_macro/element-fail.rs:84:24
|
||||||
|
|
|
|
||||||
84 | html! { <input ref=() /> };
|
84 | html! { <input ref=() /> };
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:85:24
|
--> tests/html_macro/element-fail.rs:85:24
|
||||||
|
|
|
|
||||||
85 | html! { <input ref=() ref=() /> };
|
85 | html! { <input ref=() ref=() /> };
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:86:28
|
--> tests/html_macro/element-fail.rs:86:28
|
||||||
|
|
|
|
||||||
86 | html! { <input onfocus=Some(5) /> };
|
86 | html! { <input onfocus=Some(5) /> };
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:87:27
|
--> tests/html_macro/element-fail.rs:87:27
|
||||||
|
|
|
|
||||||
87 | html! { <input string=NotToString /> };
|
87 | html! { <input string=NotToString /> };
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:88:22
|
--> tests/html_macro/element-fail.rs:88:22
|
||||||
|
|
|
|
||||||
88 | html! { <a media=Some(NotToString) /> };
|
88 | html! { <a media=Some(NotToString) /> };
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:89:21
|
--> tests/html_macro/element-fail.rs:89:21
|
||||||
|
|
|
|
||||||
89 | html! { <a href=Some(5) /> };
|
89 | html! { <a href=Some(5) /> };
|
||||||
| ^^^^^^^
|
| ^^^^^^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:90:25
|
--> tests/html_macro/element-fail.rs:90:25
|
||||||
|
|
|
|
||||||
90 | html! { <input type=() /> };
|
90 | html! { <input type=() /> };
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:91:26
|
--> tests/html_macro/element-fail.rs:91:26
|
||||||
|
|
|
|
||||||
91 | html! { <input value=() /> };
|
91 | html! { <input value=() /> };
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:92:27
|
--> tests/html_macro/element-fail.rs:92:27
|
||||||
|
|
|
|
||||||
92 | html! { <input string=NotToString /> };
|
92 | html! { <input string=NotToString /> };
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
|
||||||
warning: use of deprecated function `compile_fail::deprecated_use_of_class`: the use of `(...)` with the attribute `class` is deprecated and will be removed in version 0.19. Use the `classes!` macro instead.
|
warning: use of deprecated function `compile_fail::deprecated_use_of_class`: the use of `(...)` with the attribute `class` is deprecated and will be removed in version 0.19. Use the `classes!` macro instead.
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:80:25
|
--> tests/html_macro/element-fail.rs:80:25
|
||||||
|
|
|
|
||||||
80 | html! { <div class={("deprecated", "warning")} /> };
|
80 | html! { <div class={("deprecated", "warning")} /> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -211,13 +211,13 @@ warning: use of deprecated function `compile_fail::deprecated_use_of_class`: the
|
|||||||
= note: `#[warn(deprecated)]` on by default
|
= note: `#[warn(deprecated)]` on by default
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:36:28
|
--> tests/html_macro/element-fail.rs:36:28
|
||||||
|
|
|
|
||||||
36 | html! { <input checked=1 /> };
|
36 | html! { <input checked=1 /> };
|
||||||
| ^ expected `bool`, found integer
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:37:29
|
--> tests/html_macro/element-fail.rs:37:29
|
||||||
|
|
|
|
||||||
37 | html! { <input checked={Some(false)} /> };
|
37 | html! { <input checked={Some(false)} /> };
|
||||||
| ^^^^^^^^^^^ expected `bool`, found enum `Option`
|
| ^^^^^^^^^^^ expected `bool`, found enum `Option`
|
||||||
@ -226,13 +226,13 @@ error[E0308]: mismatched types
|
|||||||
found enum `Option<bool>`
|
found enum `Option<bool>`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:38:29
|
--> tests/html_macro/element-fail.rs:38:29
|
||||||
|
|
|
|
||||||
38 | html! { <input disabled=1 /> };
|
38 | html! { <input disabled=1 /> };
|
||||||
| ^ expected `bool`, found integer
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:39:30
|
--> tests/html_macro/element-fail.rs:39:30
|
||||||
|
|
|
|
||||||
39 | html! { <input disabled={Some(true)} /> };
|
39 | html! { <input disabled={Some(true)} /> };
|
||||||
| ^^^^^^^^^^ expected `bool`, found enum `Option`
|
| ^^^^^^^^^^ expected `bool`, found enum `Option`
|
||||||
@ -241,69 +241,69 @@ error[E0308]: mismatched types
|
|||||||
found enum `Option<bool>`
|
found enum `Option<bool>`
|
||||||
|
|
||||||
error[E0308]: mismatched types
|
error[E0308]: mismatched types
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:40:30
|
--> tests/html_macro/element-fail.rs:40:30
|
||||||
|
|
|
|
||||||
40 | html! { <option selected=1 /> };
|
40 | html! { <option selected=1 /> };
|
||||||
| ^ expected `bool`, found integer
|
| ^ expected `bool`, found integer
|
||||||
|
|
||||||
error[E0277]: the trait bound `(): IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `(): IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:43:26
|
--> tests/html_macro/element-fail.rs:43:26
|
||||||
|
|
|
|
||||||
43 | html! { <input type={()} /> };
|
43 | html! { <input type={()} /> };
|
||||||
| ^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `()`
|
| ^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `()`
|
||||||
|
|
|
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `(): IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `(): IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:44:27
|
--> tests/html_macro/element-fail.rs:44:27
|
||||||
|
|
|
|
||||||
44 | html! { <input value={()} /> };
|
44 | html! { <input value={()} /> };
|
||||||
| ^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `()`
|
| ^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `()`
|
||||||
|
|
|
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `(): IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `(): IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:45:22
|
--> tests/html_macro/element-fail.rs:45:22
|
||||||
|
|
|
|
||||||
45 | html! { <a href={()} /> };
|
45 | html! { <a href={()} /> };
|
||||||
| ^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `()`
|
| ^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `()`
|
||||||
|
|
|
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:46:28
|
--> tests/html_macro/element-fail.rs:46:28
|
||||||
|
|
|
|
||||||
46 | html! { <input string={NotToString} /> };
|
46 | html! { <input string={NotToString} /> };
|
||||||
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `NotToString`
|
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `NotToString`
|
||||||
|
|
|
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:47:23
|
--> tests/html_macro/element-fail.rs:47:23
|
||||||
|
|
|
|
||||||
47 | html! { <a media={Some(NotToString)} /> };
|
47 | html! { <a media={Some(NotToString)} /> };
|
||||||
| ^^^^^^^^^^^^^^^^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `Option<NotToString>`
|
| ^^^^^^^^^^^^^^^^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `Option<NotToString>`
|
||||||
|
|
|
|
||||||
= help: the following implementations were found:
|
= help: the following implementations were found:
|
||||||
<Option<&'static str> as IntoPropValue<Option<Cow<'static, str>>>>
|
<Option<&'static str> as IntoPropValue<Option<AttrValue>>>
|
||||||
<Option<&'static str> as IntoPropValue<Option<String>>>
|
<Option<&'static str> as IntoPropValue<Option<String>>>
|
||||||
<Option<String> as IntoPropValue<Option<Cow<'static, str>>>>
|
<Option<String> as IntoPropValue<Option<AttrValue>>>
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:48:22
|
--> tests/html_macro/element-fail.rs:48:22
|
||||||
|
|
|
|
||||||
48 | html! { <a href={Some(5)} /> };
|
48 | html! { <a href={Some(5)} /> };
|
||||||
| ^^^^^^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `Option<{integer}>`
|
| ^^^^^^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `Option<{integer}>`
|
||||||
|
|
|
|
||||||
= help: the following implementations were found:
|
= help: the following implementations were found:
|
||||||
<Option<&'static str> as IntoPropValue<Option<Cow<'static, str>>>>
|
<Option<&'static str> as IntoPropValue<Option<AttrValue>>>
|
||||||
<Option<&'static str> as IntoPropValue<Option<String>>>
|
<Option<&'static str> as IntoPropValue<Option<String>>>
|
||||||
<Option<String> as IntoPropValue<Option<Cow<'static, str>>>>
|
<Option<String> as IntoPropValue<Option<AttrValue>>>
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}`
|
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}`
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:51:28
|
--> tests/html_macro/element-fail.rs:51:28
|
||||||
|
|
|
|
||||||
51 | html! { <input onclick=1 /> };
|
51 | html! { <input onclick=1 /> };
|
||||||
| ^ expected an `Fn<(MouseEvent,)>` closure, found `{integer}`
|
| ^ expected an `Fn<(MouseEvent,)>` closure, found `{integer}`
|
||||||
@ -323,7 +323,7 @@ error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}`
|
|||||||
= note: required because of the requirements on the impl of `IntoEventCallback<MouseEvent>` for `{integer}`
|
= note: required because of the requirements on the impl of `IntoEventCallback<MouseEvent>` for `{integer}`
|
||||||
|
|
||||||
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>`
|
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>`
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:52:29
|
--> tests/html_macro/element-fail.rs:52:29
|
||||||
|
|
|
|
||||||
52 | html! { <input onclick={Callback::from(|a: String| ())} /> };
|
52 | html! { <input onclick={Callback::from(|a: String| ())} /> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -346,7 +346,7 @@ error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<Strin
|
|||||||
= note: required because of the requirements on the impl of `IntoEventCallback<MouseEvent>` for `yew::Callback<String>`
|
= note: required because of the requirements on the impl of `IntoEventCallback<MouseEvent>` for `yew::Callback<String>`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Option<{integer}>: IntoEventCallback<FocusEvent>` is not satisfied
|
error[E0277]: the trait bound `Option<{integer}>: IntoEventCallback<FocusEvent>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:53:29
|
--> tests/html_macro/element-fail.rs:53:29
|
||||||
|
|
|
|
||||||
53 | html! { <input onfocus={Some(5)} /> };
|
53 | html! { <input onfocus={Some(5)} /> };
|
||||||
| ^^^^^^^ the trait `IntoEventCallback<FocusEvent>` is not implemented for `Option<{integer}>`
|
| ^^^^^^^ the trait `IntoEventCallback<FocusEvent>` is not implemented for `Option<{integer}>`
|
||||||
@ -367,7 +367,7 @@ error[E0277]: the trait bound `Option<{integer}>: IntoEventCallback<FocusEvent>`
|
|||||||
<Option<yew::Callback<EVENT>> as IntoEventCallback<EVENT>>
|
<Option<yew::Callback<EVENT>> as IntoEventCallback<EVENT>>
|
||||||
|
|
||||||
error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:56:25
|
--> tests/html_macro/element-fail.rs:56:25
|
||||||
|
|
|
|
||||||
56 | html! { <input ref={()} /> };
|
56 | html! { <input ref={()} /> };
|
||||||
| ^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`
|
| ^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`
|
||||||
@ -375,19 +375,19 @@ error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
|||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>` is not satisfied
|
error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:57:25
|
--> tests/html_macro/element-fail.rs:57:25
|
||||||
|
|
|
|
||||||
57 | html! { <input ref={Some(NodeRef::default())} /> };
|
57 | html! { <input ref={Some(NodeRef::default())} /> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `Option<yew::NodeRef>`
|
| ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `Option<yew::NodeRef>`
|
||||||
|
|
|
|
||||||
= help: the following implementations were found:
|
= help: the following implementations were found:
|
||||||
<Option<&'static str> as IntoPropValue<Option<Cow<'static, str>>>>
|
<Option<&'static str> as IntoPropValue<Option<AttrValue>>>
|
||||||
<Option<&'static str> as IntoPropValue<Option<String>>>
|
<Option<&'static str> as IntoPropValue<Option<String>>>
|
||||||
<Option<String> as IntoPropValue<Option<Cow<'static, str>>>>
|
<Option<String> as IntoPropValue<Option<AttrValue>>>
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>`
|
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>`
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:58:29
|
--> tests/html_macro/element-fail.rs:58:29
|
||||||
|
|
|
|
||||||
58 | html! { <input onclick={Callback::from(|a: String| ())} /> };
|
58 | html! { <input onclick={Callback::from(|a: String| ())} /> };
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
@ -409,16 +409,16 @@ error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<Strin
|
|||||||
= note: the trait bound `yew::Callback<String>: IntoEventCallback<MouseEvent>` is not satisfied
|
= note: the trait bound `yew::Callback<String>: IntoEventCallback<MouseEvent>` is not satisfied
|
||||||
= note: required because of the requirements on the impl of `IntoEventCallback<MouseEvent>` for `yew::Callback<String>`
|
= note: required because of the requirements on the impl of `IntoEventCallback<MouseEvent>` for `yew::Callback<String>`
|
||||||
|
|
||||||
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<Cow<'static, str>>>` is not satisfied
|
error[E0277]: the trait bound `NotToString: IntoPropValue<Option<AttrValue>>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:60:28
|
--> tests/html_macro/element-fail.rs:60:28
|
||||||
|
|
|
|
||||||
60 | html! { <input string={NotToString} /> };
|
60 | html! { <input string={NotToString} /> };
|
||||||
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<Cow<'static, str>>>` is not implemented for `NotToString`
|
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<AttrValue>>` is not implemented for `NotToString`
|
||||||
|
|
|
|
||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:62:25
|
--> tests/html_macro/element-fail.rs:62:25
|
||||||
|
|
|
|
||||||
62 | html! { <input ref={()} /> };
|
62 | html! { <input ref={()} /> };
|
||||||
| ^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`
|
| ^^ the trait `IntoPropValue<yew::NodeRef>` is not implemented for `()`
|
||||||
@ -426,7 +426,7 @@ error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied
|
|||||||
= note: required by `into_prop_value`
|
= note: required by `into_prop_value`
|
||||||
|
|
||||||
error[E0277]: the trait bound `Cow<'static, str>: From<{integer}>` is not satisfied
|
error[E0277]: the trait bound `Cow<'static, str>: From<{integer}>` is not satisfied
|
||||||
--> $DIR/tests/html_macro/element-fail.rs:77:15
|
--> tests/html_macro/element-fail.rs:77:15
|
||||||
|
|
|
|
||||||
77 | html! { <@{55}></@> };
|
77 | html! { <@{55}></@> };
|
||||||
| ^^^^ the trait `From<{integer}>` is not implemented for `Cow<'static, str>`
|
| ^^^^ the trait `From<{integer}>` is not implemented for `Cow<'static, str>`
|
||||||
|
|||||||
@ -46,8 +46,7 @@ fn compile_pass() {
|
|||||||
|| <::std::string::String as ::std::convert::From<&::std::primitive::str>>::from("test");
|
|| <::std::string::String as ::std::convert::From<&::std::primitive::str>>::from("test");
|
||||||
let mut extra_tags_iter = ::std::iter::IntoIterator::into_iter(::std::vec!["a", "b"]);
|
let mut extra_tags_iter = ::std::iter::IntoIterator::into_iter(::std::vec!["a", "b"]);
|
||||||
|
|
||||||
let cow_none: ::std::option::Option<::std::borrow::Cow<'static, ::std::primitive::str>> =
|
let attr_val_none: ::std::option::Option<::yew::virtual_dom::AttrValue> = ::std::option::Option::None;
|
||||||
::std::option::Option::None;
|
|
||||||
|
|
||||||
::yew::html! {
|
::yew::html! {
|
||||||
<div>
|
<div>
|
||||||
@ -100,11 +99,11 @@ fn compile_pass() {
|
|||||||
}
|
}
|
||||||
}/>
|
}/>
|
||||||
|
|
||||||
<a href={::std::option::Option::Some(::std::borrow::Cow::Borrowed("http://google.com"))} media={::std::clone::Clone::clone(&cow_none)} />
|
<a href={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static("http://google.com"))} media={::std::clone::Clone::clone(&attr_val_none)} />
|
||||||
<track kind={::std::option::Option::Some(::std::borrow::Cow::Borrowed("subtitles"))} src={::std::clone::Clone::clone(&cow_none)} />
|
<track kind={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static("subtitles"))} src={::std::clone::Clone::clone(&attr_val_none)} />
|
||||||
<track kind={::std::option::Option::Some(::std::borrow::Cow::Borrowed("5"))} mixed="works" />
|
<track kind={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static("5"))} mixed="works" />
|
||||||
<input value={::std::option::Option::Some(::std::borrow::Cow::Borrowed("value"))}
|
<input value={::std::option::Option::Some(::yew::virtual_dom::AttrValue::Static("value"))}
|
||||||
onblur={::std::option::Option::Some(<::yew::Callback<::yew::events::FocusEvent> as ::std::convert::From<_>>::from(|_| ()))}
|
onblur={::std::option::Option::Some(<::yew::Callback<::yew::FocusEvent> as ::std::convert::From<_>>::from(|_| ()))}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use super::IntoPropValue;
|
use super::IntoPropValue;
|
||||||
use crate::virtual_dom::AttrValue;
|
use crate::virtual_dom::AttrValue;
|
||||||
use indexmap::IndexSet;
|
use indexmap::IndexSet;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::{
|
use std::{
|
||||||
borrow::{Borrow, Cow},
|
borrow::{Borrow, Cow},
|
||||||
hint::unreachable_unchecked,
|
hint::unreachable_unchecked,
|
||||||
@ -70,12 +71,12 @@ impl IntoPropValue<AttrValue> for Classes {
|
|||||||
fn into_prop_value(mut self) -> AttrValue {
|
fn into_prop_value(mut self) -> AttrValue {
|
||||||
if self.set.len() == 1 {
|
if self.set.len() == 1 {
|
||||||
match self.set.pop() {
|
match self.set.pop() {
|
||||||
Some(attr) => attr,
|
Some(attr) => AttrValue::Rc(Rc::from(attr)),
|
||||||
// SAFETY: the collection is checked to be non-empty above
|
// SAFETY: the collection is checked to be non-empty above
|
||||||
None => unsafe { unreachable_unchecked() },
|
None => unsafe { unreachable_unchecked() },
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Cow::Owned(self.to_string())
|
AttrValue::Owned(self.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use super::{Component, NodeRef, Scope};
|
use super::{Component, NodeRef, Scope};
|
||||||
|
use crate::virtual_dom::AttrValue;
|
||||||
use std::{borrow::Cow, rc::Rc};
|
use std::{borrow::Cow, rc::Rc};
|
||||||
|
|
||||||
/// Marker trait for types that the [`html!`] macro may clone implicitly.
|
/// Marker trait for types that the [`html!`] macro may clone implicitly.
|
||||||
@ -83,8 +84,8 @@ macro_rules! impl_into_prop {
|
|||||||
// implemented with literals in mind
|
// implemented with literals in mind
|
||||||
impl_into_prop!(|value: &'static str| -> String { value.to_owned() });
|
impl_into_prop!(|value: &'static str| -> String { value.to_owned() });
|
||||||
|
|
||||||
impl_into_prop!(|value: &'static str| -> Cow<'static, str> { Cow::Borrowed(value) });
|
impl_into_prop!(|value: &'static str| -> AttrValue { AttrValue::Static(value) });
|
||||||
impl_into_prop!(|value: String| -> Cow<'static, str> { Cow::Owned(value) });
|
impl_into_prop!(|value: String| -> AttrValue { AttrValue::Owned(value) });
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
@ -94,7 +95,7 @@ mod test {
|
|||||||
fn test_str() {
|
fn test_str() {
|
||||||
let _: String = "foo".into_prop_value();
|
let _: String = "foo".into_prop_value();
|
||||||
let _: Option<String> = "foo".into_prop_value();
|
let _: Option<String> = "foo".into_prop_value();
|
||||||
let _: Cow<'static, str> = "foo".into_prop_value();
|
let _: AttrValue = "foo".into_prop_value();
|
||||||
let _: Option<Cow<'static, str>> = "foo".into_prop_value();
|
let _: Option<AttrValue> = "foo".into_prop_value();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub mod vtext;
|
|||||||
|
|
||||||
use crate::html::{AnyScope, NodeRef};
|
use crate::html::{AnyScope, NodeRef};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use std::{borrow::Cow, collections::HashMap, hint::unreachable_unchecked, iter};
|
use std::{collections::HashMap, fmt, hint::unreachable_unchecked, iter};
|
||||||
use web_sys::{Element, Node};
|
use web_sys::{Element, Node};
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
@ -34,9 +34,72 @@ pub use self::vnode::VNode;
|
|||||||
pub use self::vtag::VTag;
|
pub use self::vtag::VTag;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use self::vtext::VText;
|
pub use self::vtext::VText;
|
||||||
|
use std::fmt::Formatter;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Attribute value
|
/// Attribute value
|
||||||
pub type AttrValue = Cow<'static, str>;
|
#[derive(Eq, PartialEq, Debug)]
|
||||||
|
pub enum AttrValue {
|
||||||
|
/// String living for `'static`
|
||||||
|
Static(&'static str),
|
||||||
|
/// Owned string
|
||||||
|
Owned(String),
|
||||||
|
/// Reference counted string
|
||||||
|
Rc(Rc<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for AttrValue {
|
||||||
|
type Target = str;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
match self {
|
||||||
|
AttrValue::Static(s) => *s,
|
||||||
|
AttrValue::Owned(s) => s.as_str(),
|
||||||
|
AttrValue::Rc(s) => &*s,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<&'static str> for AttrValue {
|
||||||
|
fn from(s: &'static str) -> Self {
|
||||||
|
AttrValue::Static(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for AttrValue {
|
||||||
|
fn from(s: String) -> Self {
|
||||||
|
AttrValue::Owned(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Rc<str>> for AttrValue {
|
||||||
|
fn from(s: Rc<str>) -> Self {
|
||||||
|
AttrValue::Rc(s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Clone for AttrValue {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
match self {
|
||||||
|
AttrValue::Static(s) => AttrValue::Static(s),
|
||||||
|
AttrValue::Owned(s) => AttrValue::Owned(s.clone()),
|
||||||
|
AttrValue::Rc(s) => AttrValue::Rc(Rc::clone(s)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for AttrValue {
|
||||||
|
fn as_ref(&self) -> &str {
|
||||||
|
&*self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for AttrValue {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "{}", self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Applies contained changes to DOM [Element]
|
/// Applies contained changes to DOM [Element]
|
||||||
trait Apply {
|
trait Apply {
|
||||||
@ -628,7 +691,7 @@ mod benchmarks {
|
|||||||
fn bench_diff_change_first() {
|
fn bench_diff_change_first() {
|
||||||
let old = sample_values();
|
let old = sample_values();
|
||||||
let mut new = old.clone();
|
let mut new = old.clone();
|
||||||
new[0] = AttrValue::Borrowed("changed");
|
new[0] = AttrValue::Static("changed");
|
||||||
|
|
||||||
let dynamic = (make_dynamic(old.clone()), make_dynamic(new.clone()));
|
let dynamic = (make_dynamic(old.clone()), make_dynamic(new.clone()));
|
||||||
let map = (make_indexed_map(old), make_indexed_map(new));
|
let map = (make_indexed_map(old), make_indexed_map(new));
|
||||||
@ -670,7 +733,7 @@ mod benchmarks {
|
|||||||
"danny", "the", "the", "calling", "glen", "glen", "down", "mountain", "",
|
"danny", "the", "the", "calling", "glen", "glen", "down", "mountain", "",
|
||||||
]
|
]
|
||||||
.iter()
|
.iter()
|
||||||
.map(|v| AttrValue::Borrowed(*v))
|
.map(|v| AttrValue::Static(*v))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,7 @@ impl<T: AccessValue> Apply for Value<T> {
|
|||||||
match (&self.0, &ancestor.0) {
|
match (&self.0, &ancestor.0) {
|
||||||
(Some(new), Some(_)) => {
|
(Some(new), Some(_)) => {
|
||||||
// Refresh value from the DOM. It might have changed.
|
// Refresh value from the DOM. It might have changed.
|
||||||
if new != &el.value() {
|
if new.as_ref() != el.value() {
|
||||||
el.set_value(new);
|
el.set_value(new);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1075,7 +1075,7 @@ mod tests {
|
|||||||
<@{"input"} value="World"/>
|
<@{"input"} value="World"/>
|
||||||
};
|
};
|
||||||
let input_vtag = assert_vtag_mut(&mut input_el);
|
let input_vtag = assert_vtag_mut(&mut input_el);
|
||||||
assert_eq!(input_vtag.value(), Some(&Cow::Borrowed("World")));
|
assert_eq!(input_vtag.value(), Some(&AttrValue::Static("World")));
|
||||||
assert!(!input_vtag.attributes.iter().any(|(k, _)| k == "value"));
|
assert!(!input_vtag.attributes.iter().any(|(k, _)| k == "value"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user