Skip to content

Commit 91a1723

Browse files
authored
Support MaybeDyn<Option<Cow<'static, str>>> and make some impls more flexible (#713)
* Add some more impls for MaybeDyn for converting from signals * Add implementations for Option<Cow<'static, str>> * More flexible From<Signal> impl for MaybeDyn * Add a test * Fix errors
1 parent d73c4f4 commit 91a1723

File tree

5 files changed

+73
-15
lines changed

5 files changed

+73
-15
lines changed

packages/sycamore-reactive/src/maybe_dyn.rs

+58-10
Original file line numberDiff line numberDiff line change
@@ -94,15 +94,25 @@ impl<T: Into<Self> + 'static> MaybeDyn<T> {
9494
}
9595
}
9696

97-
impl<T: Into<Self>> From<ReadSignal<T>> for MaybeDyn<T> {
98-
fn from(val: ReadSignal<T>) -> Self {
99-
MaybeDyn::Signal(val)
97+
impl<T: Into<Self>, U: Into<MaybeDyn<T>> + Clone> From<ReadSignal<U>> for MaybeDyn<T> {
98+
fn from(val: ReadSignal<U>) -> Self {
99+
// Check if U == T, i.e. ReadSignal<U> is actually a ReadSignal<T>.
100+
//
101+
// If so, we use a trick to convert the generic type to the concrete type. This should be
102+
// optimized out by the compiler to be zero-cost.
103+
if let Some(val) =
104+
(&mut Some(val) as &mut dyn std::any::Any).downcast_mut::<Option<ReadSignal<T>>>()
105+
{
106+
MaybeDyn::Signal(val.unwrap())
107+
} else {
108+
MaybeDyn::Derived(Rc::new(move || val.get_clone().into()))
109+
}
100110
}
101111
}
102112

103-
impl<T: Into<Self>> From<Signal<T>> for MaybeDyn<T> {
104-
fn from(val: Signal<T>) -> Self {
105-
MaybeDyn::Signal(*val)
113+
impl<T: Into<Self>, U: Into<MaybeDyn<T>> + Clone> From<Signal<U>> for MaybeDyn<T> {
114+
fn from(val: Signal<U>) -> Self {
115+
Self::from(*val)
106116
}
107117
}
108118

@@ -149,20 +159,39 @@ macro_rules! impl_into_maybe_dyn {
149159
}
150160
}
151161

162+
$crate::impl_into_maybe_dyn_with_convert!($ty; Into::into $(; $($from),*)?);
163+
};
164+
}
165+
166+
/// Create `From<U>` implementations for `MaybeDyn<T>` for a list of types.
167+
///
168+
/// Usually, you would use the [`impl_into_maybe_dyn!`] macro instead of this macro.
169+
#[macro_export]
170+
macro_rules! impl_into_maybe_dyn_with_convert {
171+
($ty:ty; $convert:expr $(; $($from:ty),*)?) => {
152172
$(
153173
$(
154174
impl From<$from> for $crate::MaybeDyn<$ty> {
155175
fn from(val: $from) -> Self {
156-
MaybeDyn::Static(val.into())
176+
MaybeDyn::Static($convert(val))
157177
}
158178
}
159179
)*
160180
)?
161181
};
162182
}
163183

164-
impl_into_maybe_dyn!(bool);
165184
impl_into_maybe_dyn!(Cow<'static, str>; &'static str, String);
185+
impl_into_maybe_dyn_with_convert!(
186+
Option<Cow<'static, str>>; |x| Some(Into::into(x));
187+
Cow<'static, str>, &'static str, String
188+
);
189+
impl_into_maybe_dyn_with_convert!(
190+
Option<Cow<'static, str>>; |x| Option::map(x, Into::into);
191+
Option<&'static str>, Option<String>
192+
);
193+
194+
impl_into_maybe_dyn!(bool);
166195

167196
impl_into_maybe_dyn!(f32);
168197
impl_into_maybe_dyn!(f64);
@@ -180,6 +209,12 @@ impl_into_maybe_dyn!(u64);
180209
impl_into_maybe_dyn!(u128);
181210
impl_into_maybe_dyn!(usize);
182211

212+
impl<T> From<Option<T>> for MaybeDyn<Option<T>> {
213+
fn from(val: Option<T>) -> Self {
214+
MaybeDyn::Static(val)
215+
}
216+
}
217+
183218
impl<T> From<Vec<T>> for MaybeDyn<Vec<T>> {
184219
fn from(val: Vec<T>) -> Self {
185220
MaybeDyn::Static(val)
@@ -209,14 +244,27 @@ mod tests {
209244
fn maybe_dyn_signal() {
210245
let _ = create_root(move || {
211246
let signal = create_signal(123);
212-
let value = MaybeDyn::from(signal);
213-
assert!(value.as_static().is_none());
247+
let value = MaybeDyn::<i32>::from(signal);
248+
assert!(matches!(value, MaybeDyn::Signal(_)));
249+
214250
assert_eq!(value.get(), 123);
215251
assert_eq!(value.get_clone(), 123);
216252
assert_eq!(value.evaluate(), 123);
217253
});
218254
}
219255

256+
#[test]
257+
fn maybe_dyn_signal_from() {
258+
let _ = create_root(move || {
259+
let signal = create_signal("abc");
260+
let value = MaybeDyn::<Cow<'static, str>>::from(signal);
261+
assert!(matches!(value, MaybeDyn::Derived(_)));
262+
263+
assert_eq!(value.get_clone(), "abc");
264+
assert_eq!(value.evaluate(), "abc");
265+
});
266+
}
267+
220268
#[test]
221269
fn maybe_dyn_derived() {
222270
let value = MaybeDyn::<i32>::from(|| 123);

packages/sycamore/tests/web/cleanup.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::cell::Cell;
22

33
use super::*;
44

5-
thread_local!(static CLEANUP_CALLED: Cell<bool> = Cell::new(false));
5+
thread_local!(static CLEANUP_CALLED: Cell<bool> = const { Cell::new(false) });
66
fn assert_cleanup_called(f: impl FnOnce()) {
77
CLEANUP_CALLED.with(|cleanup_called| {
88
cleanup_called.set(false);

packages/sycamore/tests/web/indexed.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,12 @@ fn insert_front() {
231231
#[wasm_bindgen_test]
232232
fn nested_reactivity() {
233233
let _ = create_root(|| {
234-
let count = create_signal(vec![1, 2, 3].into_iter().map(create_signal).collect());
234+
let count = create_signal(
235+
vec![1, 2, 3]
236+
.into_iter()
237+
.map(create_signal)
238+
.collect::<Vec<_>>(),
239+
);
235240

236241
let view = move || {
237242
view! {

packages/sycamore/tests/web/keyed.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,12 @@ fn insert_front() {
271271
#[wasm_bindgen_test]
272272
fn nested_reactivity() {
273273
let _ = create_root(|| {
274-
let count = create_signal(vec![1, 2, 3].into_iter().map(create_signal).collect());
274+
let count = create_signal(
275+
vec![1, 2, 3]
276+
.into_iter()
277+
.map(create_signal)
278+
.collect::<Vec<_>>(),
279+
);
275280

276281
let view = move || {
277282
view! {

packages/tools/bench/benches/reactivity.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ pub fn bench(c: &mut Criterion) {
4343
c.bench_function("reactivity_map_indexed", |b| {
4444
let root = create_root(|| {
4545
b.iter(|| {
46-
let v = create_signal((0..100).collect());
46+
let v = create_signal((0..100).collect::<Vec<_>>());
4747
let mapped = map_indexed(v, |x| x * 2);
4848
mapped.track();
4949

@@ -57,7 +57,7 @@ pub fn bench(c: &mut Criterion) {
5757
c.bench_function("reactivity_map_keyed", |b| {
5858
let root = create_root(|| {
5959
b.iter(|| {
60-
let v = create_signal((0..100).collect());
60+
let v = create_signal((0..100).collect::<Vec<_>>());
6161
let mapped = map_keyed(v, |x| x * 2, |x| *x);
6262
mapped.track();
6363

0 commit comments

Comments
 (0)