44
55use std:: collections:: { HashMap , LinkedList } ;
66
7- use crate :: props:: Color ;
7+ use crate :: props:: { AnyProp , Color } ;
88use 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