Skip to content

Commit 815dff6

Browse files
feat: allow &str and String conversion for Option<Html> (#4020)
Co-authored-by: Mattuwu <syan4@ualberta.ca>
1 parent 3827be1 commit 815dff6

3 files changed

Lines changed: 123 additions & 40 deletions

File tree

packages/yew-macro/tests/html_macro/component-fail.stderr

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -488,14 +488,14 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
488488
| required by a bound introduced by this call
489489
|
490490
= help: the following other types implement trait `IntoPropValue<T>`:
491-
&f32
492-
&f64
493-
&i128
494-
&i16
495-
&i32
496-
&i64
497-
&i8
498-
&isize
491+
`&f32` implements `IntoPropValue<Option<VNode>>`
492+
`&f32` implements `IntoPropValue<VNode>`
493+
`&f64` implements `IntoPropValue<Option<VNode>>`
494+
`&f64` implements `IntoPropValue<VNode>`
495+
`&i128` implements `IntoPropValue<Option<VNode>>`
496+
`&i128` implements `IntoPropValue<VNode>`
497+
`&i16` implements `IntoPropValue<Option<VNode>>`
498+
`&i16` implements `IntoPropValue<VNode>`
499499
and $N others
500500
note: required by a bound in `ChildPropertiesBuilder::string`
501501
--> tests/html_macro/component-fail.rs:4:17
@@ -516,14 +516,14 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
516516
| required by a bound introduced by this call
517517
|
518518
= help: the following other types implement trait `IntoPropValue<T>`:
519-
&f32
520-
&f64
521-
&i128
522-
&i16
523-
&i32
524-
&i64
525-
&i8
526-
&isize
519+
`&f32` implements `IntoPropValue<Option<VNode>>`
520+
`&f32` implements `IntoPropValue<VNode>`
521+
`&f64` implements `IntoPropValue<Option<VNode>>`
522+
`&f64` implements `IntoPropValue<VNode>`
523+
`&i128` implements `IntoPropValue<Option<VNode>>`
524+
`&i128` implements `IntoPropValue<VNode>`
525+
`&i16` implements `IntoPropValue<Option<VNode>>`
526+
`&i16` implements `IntoPropValue<VNode>`
527527
and $N others
528528
note: required by a bound in `ChildPropertiesBuilder::string`
529529
--> tests/html_macro/component-fail.rs:4:17
@@ -561,8 +561,10 @@ error[E0277]: the trait bound `u32: IntoPropValue<i32>` is not satisfied
561561
| required by a bound introduced by this call
562562
|
563563
= help: the following other types implement trait `IntoPropValue<T>`:
564-
&u32
565-
u32
564+
`&u32` implements `IntoPropValue<Option<VNode>>`
565+
`&u32` implements `IntoPropValue<VNode>`
566+
`u32` implements `IntoPropValue<Option<VNode>>`
567+
`u32` implements `IntoPropValue<VNode>`
566568
note: required by a bound in `ChildPropertiesBuilder::int`
567569
--> tests/html_macro/component-fail.rs:4:17
568570
|

packages/yew-macro/tests/html_macro/element-fail.stderr

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -465,14 +465,14 @@ error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone:
465465
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `NotToString`
466466
|
467467
= help: the following other types implement trait `IntoPropValue<T>`:
468+
`&&String` implements `IntoPropValue<Option<VNode>>`
468469
`&&String` implements `IntoPropValue<VNode>`
470+
`&&str` implements `IntoPropValue<Option<VNode>>`
469471
`&&str` implements `IntoPropValue<VNode>`
470472
`&'static [(K, V)]` implements `IntoPropValue<implicit_clone::unsync::map::IMap<K, V>>`
471473
`&'static [T]` implements `IntoPropValue<implicit_clone::unsync::array::IArray<T>>`
472474
`&'static str` implements `IntoPropValue<Classes>`
473475
`&'static str` implements `IntoPropValue<Option<String>>`
474-
`&'static str` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
475-
`&'static str` implements `IntoPropValue<String>`
476476
and $N others
477477

478478
error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
@@ -485,14 +485,15 @@ error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implici
485485
| required by a bound introduced by this call
486486
|
487487
= help: the following other types implement trait `IntoPropValue<T>`:
488+
`Option<&String>` implements `IntoPropValue<Option<VNode>>`
489+
`Option<&implicit_clone::unsync::string::IString>` implements `IntoPropValue<Option<VNode>>`
488490
`Option<&str>` implements `IntoPropValue<Option<String>>`
491+
`Option<&str>` implements `IntoPropValue<Option<VNode>>`
489492
`Option<&str>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
490-
`Option<Cow<'_, str>>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
491-
`Option<F>` implements `IntoPropValue<Option<yew::Callback<I, O>>>`
492-
`Option<Rc<str>>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
493-
`Option<String>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
494-
`Option<T>` implements `IntoPropValue<VNode>`
495-
`Option<VChild<T>>` implements `IntoPropValue<Option<ChildrenRenderer<C>>>`
493+
`Option<Arc<String>>` implements `IntoPropValue<Option<VNode>>`
494+
`Option<Arc<str>>` implements `IntoPropValue<Option<VNode>>`
495+
`Option<Cow<'_, str>>` implements `IntoPropValue<Option<VNode>>`
496+
and $N others
496497

497498
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not satisfied
498499
--> tests/html_macro/element-fail.rs:48:22
@@ -504,14 +505,15 @@ error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_
504505
| required by a bound introduced by this call
505506
|
506507
= help: the following other types implement trait `IntoPropValue<T>`:
508+
`Option<&String>` implements `IntoPropValue<Option<VNode>>`
509+
`Option<&implicit_clone::unsync::string::IString>` implements `IntoPropValue<Option<VNode>>`
507510
`Option<&str>` implements `IntoPropValue<Option<String>>`
511+
`Option<&str>` implements `IntoPropValue<Option<VNode>>`
508512
`Option<&str>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
509-
`Option<Cow<'_, str>>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
510-
`Option<F>` implements `IntoPropValue<Option<yew::Callback<I, O>>>`
511-
`Option<Rc<str>>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
512-
`Option<String>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
513-
`Option<T>` implements `IntoPropValue<VNode>`
514-
`Option<VChild<T>>` implements `IntoPropValue<Option<ChildrenRenderer<C>>>`
513+
`Option<Arc<String>>` implements `IntoPropValue<Option<VNode>>`
514+
`Option<Arc<str>>` implements `IntoPropValue<Option<VNode>>`
515+
`Option<Cow<'_, str>>` implements `IntoPropValue<Option<VNode>>`
516+
and $N others
515517

516518
error[E0277]: the trait bound `{integer}: IntoEventCallback<MouseEvent>` is not satisfied
517519
--> tests/html_macro/element-fail.rs:51:28
@@ -621,14 +623,15 @@ error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>
621623
| required by a bound introduced by this call
622624
|
623625
= help: the following other types implement trait `IntoPropValue<T>`:
626+
`Option<&String>` implements `IntoPropValue<Option<VNode>>`
627+
`Option<&implicit_clone::unsync::string::IString>` implements `IntoPropValue<Option<VNode>>`
624628
`Option<&str>` implements `IntoPropValue<Option<String>>`
629+
`Option<&str>` implements `IntoPropValue<Option<VNode>>`
625630
`Option<&str>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
626-
`Option<Cow<'_, str>>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
627-
`Option<F>` implements `IntoPropValue<Option<yew::Callback<I, O>>>`
628-
`Option<Rc<str>>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
629-
`Option<String>` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
630-
`Option<T>` implements `IntoPropValue<VNode>`
631-
`Option<VChild<T>>` implements `IntoPropValue<Option<ChildrenRenderer<C>>>`
631+
`Option<Arc<String>>` implements `IntoPropValue<Option<VNode>>`
632+
`Option<Arc<str>>` implements `IntoPropValue<Option<VNode>>`
633+
`Option<Cow<'_, str>>` implements `IntoPropValue<Option<VNode>>`
634+
and $N others
632635

633636
error[E0277]: the trait bound `yew::Callback<String>: IntoEventCallback<MouseEvent>` is not satisfied
634637
--> tests/html_macro/element-fail.rs:58:29
@@ -665,14 +668,14 @@ error[E0277]: the trait bound `NotToString: IntoPropValue<Option<implicit_clone:
665668
| ^^^^^^^^^^^ the trait `IntoPropValue<Option<implicit_clone::unsync::string::IString>>` is not implemented for `NotToString`
666669
|
667670
= help: the following other types implement trait `IntoPropValue<T>`:
671+
`&&String` implements `IntoPropValue<Option<VNode>>`
668672
`&&String` implements `IntoPropValue<VNode>`
673+
`&&str` implements `IntoPropValue<Option<VNode>>`
669674
`&&str` implements `IntoPropValue<VNode>`
670675
`&'static [(K, V)]` implements `IntoPropValue<implicit_clone::unsync::map::IMap<K, V>>`
671676
`&'static [T]` implements `IntoPropValue<implicit_clone::unsync::array::IArray<T>>`
672677
`&'static str` implements `IntoPropValue<Classes>`
673678
`&'static str` implements `IntoPropValue<Option<String>>`
674-
`&'static str` implements `IntoPropValue<Option<implicit_clone::unsync::string::IString>>`
675-
`&'static str` implements `IntoPropValue<String>`
676679
and $N others
677680

678681
error[E0277]: the trait bound `(): IntoPropValue<yew::NodeRef>` is not satisfied

packages/yew/src/html/conversion/into_prop_value.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,24 @@ macro_rules! impl_into_prop_value_via_display {
298298
self.clone().into_prop_value()
299299
}
300300
}
301+
impl IntoPropValue<Option<VNode>> for $from_ty {
302+
#[inline(always)]
303+
fn into_prop_value(self) -> Option<VNode> {
304+
Some(IntoPropValue::<VNode>::into_prop_value(self))
305+
}
306+
}
307+
impl IntoPropValue<Option<VNode>> for &$from_ty {
308+
#[inline(always)]
309+
fn into_prop_value(self) -> Option<VNode> {
310+
Some(IntoPropValue::<VNode>::into_prop_value(self))
311+
}
312+
}
313+
impl IntoPropValue<Option<VNode>> for Option<$from_ty> {
314+
#[inline(always)]
315+
fn into_prop_value(self) -> Option<VNode> {
316+
self.map(IntoPropValue::<VNode>::into_prop_value)
317+
}
318+
}
301319
};
302320
}
303321

@@ -310,6 +328,18 @@ macro_rules! impl_into_prop_value_via_attr_value {
310328
VText::new(self).into()
311329
}
312330
}
331+
impl IntoPropValue<Option<VNode>> for $from_ty {
332+
#[inline(always)]
333+
fn into_prop_value(self) -> Option<VNode> {
334+
Some(VText::new(self).into())
335+
}
336+
}
337+
impl IntoPropValue<Option<VNode>> for Option<$from_ty> {
338+
#[inline(always)]
339+
fn into_prop_value(self) -> Option<VNode> {
340+
self.map(|v| VText::new(v).into())
341+
}
342+
}
313343
};
314344
}
315345

@@ -368,6 +398,28 @@ mod test {
368398
let _: VNode = Some(true).into_prop_value();
369399
}
370400

401+
#[test]
402+
fn test_into_option_vnode() {
403+
// T -> Option<VNode>
404+
let _: Option<VNode> = "hello".into_prop_value();
405+
let _: Option<VNode> = String::from("hello").into_prop_value();
406+
let _: Option<VNode> = AttrValue::Static("hello").into_prop_value();
407+
let _: Option<VNode> = 42u32.into_prop_value();
408+
let _: Option<VNode> = true.into_prop_value();
409+
// &T -> Option<VNode>
410+
let _: Option<VNode> = (&42u32).into_prop_value();
411+
let _: Option<VNode> = (&true).into_prop_value();
412+
let s = String::from("hello");
413+
let _: Option<VNode> = (&s).into_prop_value();
414+
// Option<T> -> Option<VNode>
415+
let _: Option<VNode> = Some("hello").into_prop_value();
416+
let _: Option<VNode> = Option::<&str>::None.into_prop_value();
417+
let _: Option<VNode> = Some(String::from("hello")).into_prop_value();
418+
let _: Option<VNode> = Option::<String>::None.into_prop_value();
419+
let _: Option<VNode> = Some(42u32).into_prop_value();
420+
let _: Option<VNode> = Some(true).into_prop_value();
421+
}
422+
371423
#[test]
372424
fn test_ref_to_vnode() {
373425
let _: VNode = (&42i32).into_prop_value();
@@ -646,4 +698,30 @@ mod test {
646698
let _ = html! { <Comp foo="hello" /> };
647699
let _ = html! { <Comp /> };
648700
}
701+
702+
#[test]
703+
fn test_option_html_prop_compiles() {
704+
use crate::prelude::*;
705+
706+
#[derive(PartialEq, Properties)]
707+
pub struct Props {
708+
pub title: Option<Html>,
709+
}
710+
711+
#[component]
712+
fn Foo(props: &Props) -> Html {
713+
match &props.title {
714+
Some(title) => html! { <h1>{ title.clone() }</h1> },
715+
None => html! {},
716+
}
717+
}
718+
719+
let _ = html! { <Foo title="Title" /> };
720+
721+
let _ = html! { <Foo title={String::from("Title")} /> };
722+
723+
let _ = html! { <Foo title={Some("Title")} /> };
724+
725+
let _ = html! { <Foo title={Option::<Html>::None} /> };
726+
}
649727
}

0 commit comments

Comments
 (0)