Skip to content

Commit bf7a37f

Browse files
committed
feat: add "State::Any"
1 parent 9fa1324 commit bf7a37f

File tree

1 file changed

+109
-1
lines changed

1 file changed

+109
-1
lines changed

src/core/state.rs

Lines changed: 109 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
use std::collections::{HashMap, LinkedList};
66

7-
use crate::props::Color;
7+
use crate::props::{AnyProp, Color};
88
use crate::utils::{Email, PhoneNumber};
99

1010
/// State describes a component state
@@ -17,6 +17,7 @@ pub enum State {
1717
Vec(Vec<StateValue>),
1818
Map(HashMap<String, StateValue>),
1919
Linked(LinkedList<State>),
20+
Any(AnyProp),
2021
None,
2122
}
2223

@@ -95,6 +96,13 @@ impl State {
9596
}
9697
}
9798

99+
pub fn unwrap_any(self) -> AnyProp {
100+
match self {
101+
Self::Any(val) => val,
102+
state => panic!("Could not unwrap {state:?} as `Any`"),
103+
}
104+
}
105+
98106
/// Returns whether `State` is `State::None`
99107
pub fn is_none(&self) -> bool {
100108
matches!(self, Self::None)
@@ -233,3 +241,103 @@ impl StateValue {
233241
}
234242
}
235243
}
244+
245+
#[cfg(test)]
246+
mod tests {
247+
use crate::State;
248+
use crate::props::{PropBound, PropBoundExt};
249+
250+
#[test]
251+
fn any() {
252+
#[derive(Debug, Clone, Copy, PartialEq)]
253+
struct SomeCustomType {
254+
field1: bool,
255+
field2: bool,
256+
}
257+
258+
#[derive(Debug, Clone, Copy, PartialEq)]
259+
struct SomeDifferentCustomType {
260+
field1: bool,
261+
}
262+
263+
let input = SomeCustomType {
264+
field1: true,
265+
field2: false,
266+
};
267+
let single_value = State::Any(input.to_any_prop());
268+
269+
assert_eq!(
270+
single_value,
271+
State::Any(
272+
SomeCustomType {
273+
field1: true,
274+
field2: false
275+
}
276+
.to_any_prop()
277+
)
278+
);
279+
assert_ne!(
280+
single_value,
281+
State::Any(
282+
SomeCustomType {
283+
field1: false,
284+
field2: true
285+
}
286+
.to_any_prop()
287+
)
288+
);
289+
290+
assert_ne!(
291+
single_value,
292+
State::Any(SomeDifferentCustomType { field1: true }.to_any_prop())
293+
);
294+
295+
#[derive(Debug, Clone, PartialEq)]
296+
struct CloneableType {
297+
field1: String,
298+
}
299+
300+
let input = State::Any(
301+
CloneableType {
302+
field1: "Hello".to_string(),
303+
}
304+
.to_any_prop(),
305+
);
306+
let cloned = input.clone();
307+
308+
assert_eq!(input, cloned);
309+
let input_downcasted = match &input {
310+
State::Any(v) => v,
311+
_ => unimplemented!(),
312+
}
313+
.as_any()
314+
.downcast_ref::<CloneableType>()
315+
.expect("Erased type should be CloneableType");
316+
let cloned_downcasted = match &cloned {
317+
State::Any(v) => v,
318+
_ => unimplemented!(),
319+
}
320+
.as_any()
321+
.downcast_ref::<CloneableType>()
322+
.expect("Erased type should be CloneableType");
323+
// should be cloned and so not have the same memory pointer
324+
assert_ne!(
325+
input_downcasted.field1.as_ptr(),
326+
cloned_downcasted.field1.as_ptr()
327+
);
328+
329+
let mut changed_data = cloned;
330+
331+
let downcasted = match &mut changed_data {
332+
State::Any(v) => v,
333+
_ => unimplemented!(),
334+
}
335+
.as_any_mut()
336+
.downcast_mut::<CloneableType>()
337+
.expect("Erased type should be CloneableType");
338+
339+
downcasted.field1 = "Changed later".to_string();
340+
341+
assert_ne!(input_downcasted, downcasted);
342+
}
343+
}

0 commit comments

Comments
 (0)