Skip to content

Commit b007219

Browse files
Better ImplicitClone ergnomics (#3508)
* Use cheap-to-clone types more * Use IArray in NodeSeq & add IntoPropValue for &AttrValue * Add function get_mut() on VChild to make things easier * Use AttrValue in timer_functional example * fix VList PartialEq * extract implicit-clone as workspace dep and bump to 0.5.1 * docs: advocate using IArray and IMap instead of Vec and HashMap * docs: AI translation for lifecycles.mdx in Japanese and simplified Chinese --------- Co-authored-by: Mattuwu <syan4@ualberta.ca>
1 parent 1afb054 commit b007219

File tree

112 files changed

+6266
-812
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+6266
-812
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,4 @@ unexpected_cfgs = { level = "warn", check-cfg = [
3030
]}
3131
[workspace.dependencies]
3232
tokio = { version = "1.47.1" }
33+
implicit-clone = { version = "0.5.1" }

examples/immutable/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
implicit-clone = { version = "0.5", features = ["map"] }
9+
implicit-clone = { workspace = true, features = ["map"] }
1010
wasm-bindgen = "0.2"
1111
web-sys = "0.3"
1212
yew = { path = "../../packages/yew", features = ["csr"] }

examples/nested_list/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ edition = "2021"
66
license = "MIT OR Apache-2.0"
77

88
[dependencies]
9+
implicit-clone = { workspace = true }
910
log = "0.4"
1011
wasm-logger = "0.2"
1112
yew = { path = "../../packages/yew", features = ["csr"] }

examples/nested_list/src/list.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
use std::rc::Rc;
2-
1+
use implicit_clone::unsync::IArray;
32
use yew::prelude::*;
43
use yew::virtual_dom::VChild;
54

@@ -14,9 +13,9 @@ pub enum Msg {
1413
#[derive(Clone, PartialEq, Properties)]
1514
pub struct Props {
1615
#[prop_or_default]
17-
pub header: Vec<VChild<ListHeader>>,
16+
pub header: IArray<VChild<ListHeader>>,
1817
#[prop_or_default]
19-
pub children: Vec<VChild<ListItem>>,
18+
pub children: IArray<VChild<ListItem>>,
2019

2120
pub on_hover: Callback<Hovered>,
2221
pub weak_link: WeakComponentLink<List>,
@@ -56,9 +55,9 @@ impl Component for List {
5655
html! {
5756
<div class="list-container" {onmouseover}>
5857
<div class={classes!("list", inactive)}>
59-
{ ctx.props().header.clone() }
58+
{ &ctx.props().header }
6059
<div class="items">
61-
{ Self::view_items(ctx.props().children.clone()) }
60+
{ Self::view_items(&ctx.props().children) }
6261
</div>
6362
</div>
6463
</div>
@@ -67,13 +66,13 @@ impl Component for List {
6766
}
6867

6968
impl List {
70-
fn view_items(children: Vec<VChild<ListItem>>) -> Html {
69+
fn view_items(children: &IArray<VChild<ListItem>>) -> Html {
7170
children
72-
.into_iter()
71+
.iter()
7372
.filter(|c| !c.props.hide)
7473
.enumerate()
7574
.map(|(i, mut c)| {
76-
let props = Rc::make_mut(&mut c.props);
75+
let props = c.get_mut();
7776
props.name = format!("#{} - {}", i + 1, props.name).into();
7877
c
7978
})

examples/nested_list/src/main.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,16 +40,14 @@ impl<COMP: Component> PartialEq for WeakComponentLink<COMP> {
4040
}
4141
}
4242

43-
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
43+
#[derive(Debug, Clone, ImplicitClone, PartialEq, Eq, Hash)]
4444
pub enum Hovered {
4545
Header,
4646
Item(AttrValue),
4747
List,
4848
None,
4949
}
5050

51-
impl ImplicitClone for Hovered {}
52-
5351
impl fmt::Display for Hovered {
5452
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
5553
write!(

examples/timer/src/main.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use gloo::console::{self, Timer};
22
use gloo::timers::callback::{Interval, Timeout};
3-
use yew::{html, Component, Context, Html};
3+
use yew::prelude::*;
44

55
pub enum Msg {
66
StartTimeout,
@@ -13,7 +13,7 @@ pub enum Msg {
1313

1414
pub struct App {
1515
time: String,
16-
messages: Vec<&'static str>,
16+
messages: Vec<AttrValue>,
1717
_standalone: (Interval, Interval),
1818
interval: Option<Interval>,
1919
timeout: Option<Timeout>,
@@ -68,7 +68,7 @@ impl Component for App {
6868
self.messages.clear();
6969
console::clear!();
7070

71-
self.messages.push("Timer started!");
71+
self.log("Timer started!");
7272
self.console_timer = Some(Timer::new("Timer"));
7373
true
7474
}
@@ -82,18 +82,18 @@ impl Component for App {
8282
self.messages.clear();
8383
console::clear!();
8484

85-
self.messages.push("Interval started!");
85+
self.log("Interval started!");
8686
true
8787
}
8888
Msg::Cancel => {
8989
self.cancel();
90-
self.messages.push("Canceled!");
90+
self.log("Canceled!");
9191
console::warn!("Canceled!");
9292
true
9393
}
9494
Msg::Done => {
9595
self.cancel();
96-
self.messages.push("Done!");
96+
self.log("Done!");
9797

9898
// todo weblog
9999
// ConsoleService::group();
@@ -107,7 +107,7 @@ impl Component for App {
107107
true
108108
}
109109
Msg::Tick => {
110-
self.messages.push("Tick...");
110+
self.log("Tick...");
111111
// todo weblog
112112
// ConsoleService::count_named("Tick");
113113
true
@@ -139,14 +139,20 @@ impl Component for App {
139139
{ &self.time }
140140
</div>
141141
<div id="messages">
142-
{ for self.messages.iter().map(|message| html! { <p>{ *message }</p> }) }
142+
{ for self.messages.iter().map(|message| html! { <p>{ message }</p> }) }
143143
</div>
144144
</div>
145145
</>
146146
}
147147
}
148148
}
149149

150+
impl App {
151+
fn log(&mut self, message: impl Into<AttrValue>) {
152+
self.messages.push(message.into());
153+
}
154+
}
155+
150156
fn main() {
151157
yew::Renderer::<App>::new().render();
152158
}

examples/timer_functional/src/main.rs

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,34 @@ enum TimerAction {
1818

1919
#[derive(Clone, Debug)]
2020
struct TimerState {
21-
messages: Vec<&'static str>,
21+
messages: Messages,
2222
interval_handle: Option<Rc<Interval>>,
2323
timeout_handle: Option<Rc<Timeout>>,
2424
}
2525

26+
#[derive(Clone, Debug, Default, PartialEq, Eq)]
27+
struct Messages(Vec<AttrValue>);
28+
29+
impl Messages {
30+
fn log(&mut self, message: impl Into<AttrValue>) {
31+
self.0.push(message.into());
32+
}
33+
}
34+
35+
impl std::ops::Deref for Messages {
36+
type Target = Vec<AttrValue>;
37+
38+
fn deref(&self) -> &Self::Target {
39+
&self.0
40+
}
41+
}
42+
43+
impl FromIterator<&'static str> for Messages {
44+
fn from_iter<T: IntoIterator<Item = &'static str>>(it: T) -> Self {
45+
Messages(it.into_iter().map(Into::into).collect())
46+
}
47+
}
48+
2649
impl PartialEq for TimerState {
2750
fn eq(&self, other: &Self) -> bool {
2851
self.messages == other.messages
@@ -37,26 +60,26 @@ impl Reducible for TimerState {
3760
match action {
3861
TimerAction::Add(message) => {
3962
let mut messages = self.messages.clone();
40-
messages.push(message);
63+
messages.log(message);
4164
Rc::new(TimerState {
4265
messages,
4366
interval_handle: self.interval_handle.clone(),
4467
timeout_handle: self.timeout_handle.clone(),
4568
})
4669
}
4770
TimerAction::SetInterval(t) => Rc::new(TimerState {
48-
messages: vec!["Interval started!"],
71+
messages: ["Interval started!"].into_iter().collect(),
4972
interval_handle: Some(Rc::from(t)),
5073
timeout_handle: self.timeout_handle.clone(),
5174
}),
5275
TimerAction::SetTimeout(t) => Rc::new(TimerState {
53-
messages: vec!["Timer started!!"],
76+
messages: ["Timer started!!"].into_iter().collect(),
5477
interval_handle: self.interval_handle.clone(),
5578
timeout_handle: Some(Rc::from(t)),
5679
}),
5780
TimerAction::TimeoutDone => {
5881
let mut messages = self.messages.clone();
59-
messages.push("Done!");
82+
messages.log("Done!");
6083
Rc::new(TimerState {
6184
messages,
6285
interval_handle: self.interval_handle.clone(),
@@ -65,7 +88,7 @@ impl Reducible for TimerState {
6588
}
6689
TimerAction::Cancel => {
6790
let mut messages = self.messages.clone();
68-
messages.push("Canceled!");
91+
messages.log("Canceled!");
6992
Rc::new(TimerState {
7093
messages,
7194
interval_handle: None,
@@ -94,7 +117,7 @@ fn clock() -> Html {
94117
#[function_component]
95118
fn App() -> Html {
96119
let state = use_reducer(|| TimerState {
97-
messages: Vec::new(),
120+
messages: Default::default(),
98121
interval_handle: None,
99122
timeout_handle: None,
100123
});
@@ -105,7 +128,7 @@ fn App() -> Html {
105128
.iter()
106129
.map(|message| {
107130
key += 1;
108-
html! { <p key={ key }>{ *message }</p> }
131+
html! { <p {key}>{ message }</p> }
109132
})
110133
.collect();
111134

packages/yew-macro/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ rustversion = "1"
2828
[dev-dependencies]
2929
trybuild = "1"
3030
yew = { path = "../yew" }
31+
implicit-clone = { workspace = true }
3132

3233
[lints]
3334
workspace = true

packages/yew-macro/tests/html_macro/component-pass.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ impl ::yew::Component for Container {
5959
}
6060
}
6161

62-
#[derive(::std::clone::Clone, ::std::cmp::PartialEq)]
62+
#[derive(::std::clone::Clone, ::implicit_clone::ImplicitClone, ::std::cmp::PartialEq)]
6363
pub enum ChildrenVariants {
6464
Child(::yew::virtual_dom::VChild<Child>),
6565
AltChild(::yew::virtual_dom::VChild<AltChild>),

0 commit comments

Comments
 (0)