1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! Macros used with tests

/// Creates TestProbe matcher function from the user specified block of code
///
/// # Examples
///
/// ```
/// matcher!(v => {
///     if let Some(m) = v.downcast_ref::<some_actor::SomeMsg>() {
///         if m.data > 100 {
///             true
///         } else {
///             false
///         }
///     } else {
///         false
///     }
/// });
/// ```
#[macro_export]
macro_rules! matcher {
        ($value:ident => $body:expr) => {
            Box::new(move |$value: Message| {
                $body
            })
        };
    }

/// Creates TestProbe matcher function which match specified message type.
///
/// # Examples
///
/// ```
///  type_matcher!(some_actor::SomeMsg);
/// ```
///
#[macro_export]
macro_rules! type_matcher {
        ($t:path) => {
            Box::new(move |v: Message| {
                if let Some(_) = v.get().downcast_ref::<$t>() {
                   true
                } else {
                    false
                }
            })
        };
    }

/// Creates TestProbe matcher function which match specified message by match arm. Match arm must be
/// specified without guards.
///
/// # Examples
///
/// ```
///  type_matcher!(some_actor::SomeMsg => some_actor::SomeMsg { data: 100 });
///
/// // Message type => Match arm
///
/// ```
///
#[macro_export]
macro_rules! pat_matcher {
        ($t:path => $pat:pat) => {
            Box::new(move |v: Message| {
                if let Some(m) = v.get().downcast_ref::<$t>() {
                    match m {
                         $pat => true,
                         _ => false
                    }
                } else {
                    false
                }
            })
        };
    }

/// Creates TestProbe matcher function which match specified message type and if is was success,
/// apply specified user function to the result.
///
/// # Examples
///
/// ```
/// extended_type_matcher!(some_actor::SomeMsg, v => {
///     if v.data > 100 {
///         true
///     } else {
///         false
///     }
/// });
///
/// // Inner function must return bool value
///
/// ```
///
#[macro_export]
macro_rules! extended_type_matcher {
        ($t:path , $v:ident => $body:expr) => {
            Box::new(move |v: Message| {
                if let Some($v) = v.get().downcast_ref::<$t>() {
                   $body
                } else {
                    false
                }
            })
        };
    }

/// Extract actor object from TestActorRef. This object is immutable and may be used for reversion
/// of the internal actor's state. For use this macros, target actor must implement the as_any
/// method from the Actor trait. Without satisfying this condition, macros will cause panic.
///
/// # Examples
///
/// ```
/// in_state! (target, Foo, actor => {
///     assert_eq!(actor.data, 599);
/// });
///
/// // target - TestActorRef
/// // Foo - actor type under actor reference
/// ```
///
#[macro_export]
macro_rules! in_state {
        ($r:ident , $t:path, $a:ident => $e:expr) => {
            {
                let target_any = $r.as_any();
                let sd = target_any.downcast_ref::<Box<TestLocalActorRef>>().unwrap();
                let mut actor = sd.actor.lock().unwrap();
                let actor = actor.as_any();
                let $a = actor.downcast_ref::<$t>().unwrap();
                $e;
            }
        };
    }

/// Casts some Message to the specified type and call user function with this value. Macro
/// may be used as extractor of data from a messages, because he may return values from itself
/// based on the data from a message
///
/// # Example
///
/// ```
/// // As validator
/// cast!(msg, responses::MsgResponse, m => {
///     assert_eq!(m.data, 99);
/// });
///
/// // As extractor
/// let data = cast!(msg, responses::MsgResponse, m => {
///     m.data;
/// });
/// ```
///
/// # Panic
///
/// Macro will case panic, if downcast operation will be failed.
///
#[macro_export]
macro_rules! cast {
        ($m:ident , $t:path , $v:ident => $body:expr) => {
            {
                let msg = $m.get();

                if let Some($v) = msg.downcast_ref::<$t>() {
                    $body
                } else {
                    panic!("Unable to cast a message");
                }
            }
        };
    }