Skip to content

Commit 7f6c3ae

Browse files
authored
Fix macros to allow an arbitrary number of properties in Xilem views (#1161)
Fixes the issues encountered in #1099.
1 parent 07d1150 commit 7f6c3ae

File tree

2 files changed

+71
-74
lines changed

2 files changed

+71
-74
lines changed

xilem/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
// https://github.com/rust-lang/rust/pull/130025
130130
#![expect(clippy::allow_attributes_without_reason, reason = "Deferred: Noisy")]
131131

132+
pub use masonry;
132133
pub use masonry::kurbo::{Affine, Vec2};
133134
pub use masonry::parley::Alignment as TextAlign;
134135
pub use masonry::parley::style::FontWeight;

xilem/src/property_tuple.rs

Lines changed: 70 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Copyright 2025 the Xilem Authors
22
// SPDX-License-Identifier: Apache-2.0
33

4-
use masonry::core::{Properties, Property, Widget, WidgetMut};
4+
use masonry::core::{Properties, Widget, WidgetMut};
55

66
/// Helper trait implemented for all tuples of `Option<SomeProperty>` up to 12 items.
77
pub trait PropertyTuple {
@@ -16,78 +16,6 @@ pub trait PropertyTuple {
1616
fn rebuild_properties(&self, prev: &Self, target: &mut WidgetMut<'_, impl Widget>);
1717
}
1818

19-
impl<P0: Property + Eq + Clone> PropertyTuple for (Option<P0>,) {
20-
fn build_properties(&self) -> Properties {
21-
let mut props = Properties::new();
22-
if let Some(prop) = self.0.clone() {
23-
props.insert(prop);
24-
}
25-
props
26-
}
27-
28-
fn rebuild_properties(&self, prev: &Self, target: &mut WidgetMut<'_, impl Widget>) {
29-
if self.0 != prev.0 {
30-
if let Some(prop) = self.0.clone() {
31-
target.insert_prop(prop);
32-
} else {
33-
target.remove_prop::<P0>();
34-
}
35-
}
36-
}
37-
}
38-
39-
// We expect to use the ${index} metavariable here once it's stable
40-
// https://veykril.github.io/tlborm/decl-macros/minutiae/metavar-expr.html
41-
macro_rules! impl_property_tuple {
42-
($($Type: ident, $idx: tt);+) => {
43-
44-
impl<$($Type,)+> PropertyTuple for ($(Option<$Type>,)+)
45-
where $($Type: Property + PartialEq + Clone,)+
46-
{
47-
fn build_properties(&self) -> Properties {
48-
let mut props = Properties::new();
49-
$(
50-
if let Some(prop) = self.$idx.clone() {
51-
props.insert(prop);
52-
}
53-
)+
54-
props
55-
}
56-
57-
fn rebuild_properties(&self, prev: &Self, target: &mut WidgetMut<'_, impl Widget>) {
58-
$(
59-
if self.$idx != prev.$idx {
60-
if let Some(prop) = self.$idx.clone() {
61-
target.insert_prop(prop);
62-
} else {
63-
target.remove_prop::<$Type>();
64-
}
65-
}
66-
)+
67-
}
68-
69-
}
70-
71-
};
72-
}
73-
74-
// The (P0,) one-view tuple case is covered outside the macro,
75-
// for easier code editing.
76-
77-
impl_property_tuple!(P0, 0; P1, 1);
78-
impl_property_tuple!(P0, 0; P1, 1; P2, 2);
79-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3);
80-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4);
81-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5);
82-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5; P6, 6);
83-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5; P6, 6; P7, 7);
84-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5; P6, 6; P7, 7; P8, 8);
85-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5; P6, 6; P7, 7; P8, 8; P9, 9);
86-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5; P6, 6; P7, 7; P8, 8; P9, 9; P10, 10);
87-
impl_property_tuple!(P0, 0; P1, 1; P2, 2; P3, 3; P4, 4; P5, 5; P6, 6; P7, 7; P8, 8; P9, 9; P10, 10; P11, 11);
88-
89-
// ---
90-
9119
// We expect to use the ${index} metavariable here once it's stable
9220
// https://veykril.github.io/tlborm/decl-macros/minutiae/metavar-expr.html
9321

@@ -154,7 +82,53 @@ macro_rules! __declare_property_tuple_loop {
15482
$Type: ident, $idx: tt;
15583
)+
15684
) => {
157-
type $Props = ($(Option<$Type>,)+);
85+
86+
/// Properties used by the
87+
#[doc = stringify!($Self)]
88+
/// view.
89+
///
90+
/// This type implements the `PropertyTuple` trait.
91+
/// Its methods should be used when writing `View::build()`
92+
/// and `View::rebuild()` methods.
93+
pub struct $Props($(Option<$Type>,)+);
94+
95+
// We implement Default directly instead of calling `#[derive(Default)]`.
96+
// The code should compile slightly faster this way.
97+
impl ::std::default::Default for $Props {
98+
fn default() -> Self {
99+
$Props {
100+
$(
101+
$idx: ::std::default::Default::default(),
102+
)+
103+
}
104+
}
105+
}
106+
107+
impl $crate::property_tuple::PropertyTuple for $Props
108+
{
109+
fn build_properties(&self) -> $crate::masonry::core::Properties {
110+
let mut props = $crate::masonry::core::Properties::new();
111+
$(
112+
if let Some(prop) = self.$idx.clone() {
113+
props.insert(prop);
114+
}
115+
)+
116+
props
117+
}
118+
119+
fn rebuild_properties(&self, prev: &Self, target: &mut $crate::masonry::core::WidgetMut<'_, impl $crate::masonry::core::Widget>) {
120+
$(
121+
if self.$idx != prev.$idx {
122+
if let Some(prop) = self.$idx.clone() {
123+
target.insert_prop(prop);
124+
} else {
125+
target.remove_prop::<$Type>();
126+
}
127+
}
128+
)+
129+
}
130+
}
131+
158132

159133
$(
160134
$crate::__declare_property_tuple_inner!($Self; $Type; $idx;);
@@ -181,3 +155,25 @@ macro_rules! __declare_property_tuple_inner {
181155
}
182156
};
183157
}
158+
159+
// Example impl for code editing
160+
#[cfg(false)]
161+
impl<P0: Property + Eq + Clone> PropertyTuple for (Option<P0>,) {
162+
fn build_properties(&self) -> Properties {
163+
let mut props = Properties::new();
164+
if let Some(prop) = self.0.clone() {
165+
props.insert(prop);
166+
}
167+
props
168+
}
169+
170+
fn rebuild_properties(&self, prev: &Self, target: &mut WidgetMut<'_, impl Widget>) {
171+
if self.0 != prev.0 {
172+
if let Some(prop) = self.0.clone() {
173+
target.insert_prop(prop);
174+
} else {
175+
target.remove_prop::<P0>();
176+
}
177+
}
178+
}
179+
}

0 commit comments

Comments
 (0)