1use std::fmt::Display;
2
3use futures_signals::signal::{DedupeMap, Mutable, Signal, SignalExt};
4
5use crate::prelude::GenericNode;
6
7pub trait SideEffect<Attr: EffectAttribute<Handler = Self>, Effect, Node> {
18 fn effect(&self, node: &Node, attr: Attr, effect: Effect);
19}
20
21pub trait EffectAttribute {
22 type Handler;
23 fn read_as_attr(&self) -> String;
24}
25
26pub struct DefaultAttributeEffect;
27
28pub struct DefaultAttrStr(pub &'static str);
29
30impl EffectAttribute for DefaultAttrStr {
31 type Handler = DefaultAttributeEffect;
32 fn read_as_attr(&self) -> String {
33 self.0.to_owned()
34 }
35}
36
37macro_rules! impl_simple_effect {
38 ($effect_type:ty) => {
39 impl<Node: GenericNode> SideEffect<DefaultAttrStr, $effect_type, Node>
40 for DefaultAttributeEffect
41 {
42 fn effect(&self, node: &Node, attr: DefaultAttrStr, effect: $effect_type) {
43 node.set_attribute(attr.0, &effect.to_string())
44 }
45 }
46 };
47}
48
49impl_simple_effect!(&str);
51impl_simple_effect!(String);
52impl_simple_effect!(&String);
53impl_simple_effect!(bool);
54impl_simple_effect!(usize);
55impl_simple_effect!(i8);
56impl_simple_effect!(i64);
57impl_simple_effect!(i32);
58impl_simple_effect!(i128);
59impl_simple_effect!(u8);
60impl_simple_effect!(u16);
61impl_simple_effect!(u32);
62impl_simple_effect!(u64);
63impl_simple_effect!(u128);
64
65impl<Node: GenericNode, A: Display + 'static + Clone + PartialEq>
83 SideEffect<DefaultAttrStr, Mutable<A>, Node> for DefaultAttributeEffect
84{
85 fn effect(&self, node: &Node, attr: DefaultAttrStr, effect: Mutable<A>) {
86 let dom = node.clone();
87 let future = SignalExt::dedupe_map(effect.signal_cloned(), move |value| {
88 GenericNode::set_attribute(&dom, attr.0, &value.to_string());
89 })
90 .to_future();
91 node.effect(future);
92 }
93}
94
95impl<
96 Node: GenericNode,
97 F: FnMut(&mut <S as Signal>::Item) -> A + 'static,
98 S: Signal + 'static,
99 A: Display + 'static + Clone + PartialEq,
100 > SideEffect<DefaultAttrStr, DedupeMap<S, F>, Node> for DefaultAttributeEffect
101where
102 <S as Signal>::Item: PartialEq,
103{
104 fn effect(&self, node: &Node, attr: DefaultAttrStr, effect: DedupeMap<S, F>) {
105 let dom = node.clone();
106 let future = SignalExt::dedupe_map(effect, move |value| {
107 GenericNode::set_attribute(&dom, attr.0, &value.to_string());
108 })
109 .to_future();
110 node.effect(future);
111 }
112}
113
114use futures_signals::signal::Dedupe;
115
116impl<Node: GenericNode, S: Signal<Item = A> + 'static, A: Display + 'static + Copy + PartialEq>
117 SideEffect<DefaultAttrStr, Dedupe<S>, Node> for DefaultAttributeEffect
118where
119 <S as Signal>::Item: PartialEq,
120{
121 fn effect(&self, node: &Node, attr: DefaultAttrStr, effect: Dedupe<S>) {
122 let dom = node.clone();
123 let future = SignalExt::dedupe_map(effect, move |value| {
124 GenericNode::set_attribute(&dom, attr.0, &value.to_string());
125 })
126 .to_future();
127 node.effect(future);
128 }
129}
130
131use futures_signals::signal::DedupeCloned;
132
133impl<
134 Node: GenericNode,
135 S: Signal<Item = A> + 'static,
136 A: Display + 'static + Clone + PartialEq,
137 > SideEffect<DefaultAttrStr, DedupeCloned<S>, Node> for DefaultAttributeEffect
138where
139 <S as Signal>::Item: PartialEq,
140{
141 fn effect(&self, node: &Node, attr: DefaultAttrStr, effect: DedupeCloned<S>) {
142 let dom = node.clone();
143 let future = SignalExt::dedupe_map(effect, move |value| {
144 GenericNode::set_attribute(&dom, attr.0, &value.to_string());
145 })
146 .to_future();
147 node.effect(future);
148 }
149}
150
151use futures_signals::signal::Map;
152
153impl<
154 Node: GenericNode,
155 F: FnMut(<S as Signal>::Item) -> A + 'static,
156 S: Signal + 'static,
157 A: Display + 'static + Clone + PartialEq,
158 > SideEffect<DefaultAttrStr, Map<S, F>, Node> for DefaultAttributeEffect
159where
160 <S as Signal>::Item: PartialEq,
161{
162 fn effect(&self, node: &Node, attr: DefaultAttrStr, effect: Map<S, F>) {
163 let dom = node.clone();
164 let future = SignalExt::map(effect, move |value| {
165 GenericNode::set_attribute(&dom, attr.0, &value.to_string());
166 })
167 .to_future();
168 node.effect(future);
169 }
170}