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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
//! Nodes that have a single child and whose status is some function of the
//! child's status.
use node::{Node, Internals, IdType};
use status::Status;

/// Implements a generic Decorator node
pub struct Decorator
{
	/// Function that is performed on the child's status
	func: Box<Fn(Status) -> Status>,

	/// Child node
	child: Node,
}
impl Decorator
{
	/// Creates a new Decorator node with the given child and function
	pub fn new(child: Node, func: Box<Fn(Status) -> Status>) -> Node
	{
		let internals = Decorator { func: func, child: child };
		Node::new(internals)
	}
}
impl Internals for Decorator
{
	fn tick(&mut self) -> Status
	{
		// If the child has already run, this shouldn't change results since it will
		// just return its last status
		let child_status = self.child.tick();

		// Now run it through the function
		(*self.func)(child_status)
	}

	fn reset(&mut self)
	{
		self.child.reset();
	}

	fn children(&self) -> Vec<&Node>
	{
		vec![&self.child]
	}

	fn children_ids(&self) -> Vec<IdType>
	{
		vec![self.child.id()]
	}

	fn type_name(&self) -> &'static str
	{
		"Decorator"
	}
}

/// Implements a node that will reset its child after the child succeeds or fails
pub struct Reset
{
	/// Child node
	child: Node,

	/// Optional number of times to do the reset
	attempt_limit: Option<u32>,

	/// Number of times the child has been reset
	attempts: u32,
}
impl Reset
{
	/// Creates a new Reset node that will reset the child indefinitely
	pub fn new(child: Node) -> Node
	{
		let internals = Reset {
			child: child,
			attempt_limit: None,
			attempts: 0,
		};
		Node::new(internals)
	}

	/// Creates a new Reset node that will reset the child a limited number of times
	pub fn with_limit(child: Node, limit: u32) -> Node
	{
		let internals = Reset {
			child: child,
			attempt_limit: Some(limit),
			attempts: 0,
		};
		Node::new(internals)
	}
}
impl Internals for Reset
{
	fn tick(&mut self) -> Status
	{
		// First, get the last status of the child
		let child_last_status = self.child.status();

		// If the child wasn't Running (or already reset), we need to reset it... if the count allows
		let reset = child_last_status.is_done()
		            && (self.attempt_limit == None
		            || self.attempt_limit.unwrap() > self.attempts);
		if reset {
			// Theoretically, this could overflow if there is no attempt limit. But, if
			// does, then the user really didn't plan - the node should never tick that
			// many times in any situation.
			self.child.reset();
			self.attempts += 1;
		}

		// Now tick the child
		self.child.tick()
	}

	fn reset(&mut self)
	{
		// Reset our attempt count
		self.attempts = 0;

		// Reset the child
		self.child.reset();
	}

	fn children(&self) -> Vec<&Node>
	{
		vec![&self.child]
	}

	fn children_ids(&self) -> Vec<IdType>
	{
		vec![self.child.id()]
	}

	fn type_name(&self) -> &'static str
	{
		"Reset"
	}
}

/// Implements a node that will reset its child after the child fails
pub struct Retry
{
	/// Child node
	child: Node,

	/// Optional number of times to do the reset
	attempt_limit: Option<u32>,

	/// Number of times the child has been reset
	attempts: u32,
}
impl Retry
{
	/// Creates a new Retry node that will retry the child indefinitely
	pub fn new(child: Node) -> Node
	{
		let internals = Retry {
			child: child,
			attempt_limit: None,
			attempts: 0,
		};
		Node::new(internals)
	}

	/// Creates a new Retry node that will retry the child a limited number of times
	pub fn with_limit(child: Node, limit: u32) -> Node
	{
		let internals = Retry {
			child: child,
			attempt_limit: Some(limit),
			attempts: 0,
		};
		Node::new(internals)
	}
}
impl Internals for Retry
{
	fn tick(&mut self) -> Status
	{
		// First, get the last status of the child
		let child_last_status = self.child.status();

		// If the child failed, we need to retry it... if the count allows
		let reset = child_last_status == Status::Failed
		            && (self.attempt_limit == None
		            || self.attempt_limit.unwrap() > self.attempts);
		if reset {
			// Theoretically, this could overflow if there is no attempt limit. But, if
			// does, then the user really didn't plan - the node should never tick that
			// many times in any situation.
			self.child.reset();
			self.attempts += 1;
		}

		// Now tick the child
		self.child.tick()
	}

	fn reset(&mut self)
	{
		// Reset our own status
		self.attempts = 0;

		// Reset the child
		self.child.reset();
	}

	fn children(&self) -> Vec<&Node>
	{
		vec![&self.child]
	}

	fn children_ids(&self) -> Vec<IdType>
	{
		vec![self.child.id()]
	}

	fn type_name(&self) -> &'static str
	{
		"Retry"
	}
}

#[cfg(test)]
mod test
{
	use status::Status;
	use std_nodes::*;

	fn rotate(s: Status) -> Status
	{
		match s {
			Status::Initialized => Status::Running,
			Status::Running => Status::Succeeded,
			Status::Succeeded => Status::Failed,
			Status::Failed => Status::Initialized,
		}
	}

	#[test]
	fn check_decorator()
	{
		// Test the first rotation
		let suc_child = YesTick::new(Status::Succeeded);
		let mut suc_dec = Decorator::new(suc_child, Box::new(rotate));
		let suc_status = suc_dec.tick();
		drop(suc_dec);
		assert_eq!(suc_status, rotate(Status::Succeeded));

		// Test the second rotation
		let run_child = YesTick::new(Status::Running);
		let mut run_dec = Decorator::new(run_child, Box::new(rotate));
		let run_status = run_dec.tick();
		drop(run_dec);
		assert_eq!(run_status, rotate(Status::Running));

		// Test the final rotation
		let fail_child = YesTick::new(Status::Failed);
		let mut fail_dec = Decorator::new(fail_child, Box::new(rotate));
		let fail_status = fail_dec.tick();
		drop(fail_dec);
		assert_eq!(fail_status, rotate(Status::Failed));
	}

	#[test]
	fn check_reset()
	{
		// No good way to test ticking indefinitely, so we'll tick a
		// specified number of times
		let child = CountedTick::new(Status::Succeeded, 5, true);
		let mut reset = Reset::with_limit(child, 5);

		// Tick it five times
		let mut status = Status::Running;
		for _ in 0..5 {
			status = reset.tick();
		}

		// Drop the node so the testing nodes can panic
		drop(reset);

		// Now make sure we got the right output
		assert_eq!(status, Status::Succeeded);
	}

	#[test]
	fn check_retry()
	{
		// We can test to make sure that the "indefinite" only ticks while failed
		let child1 = CountedTick::new(Status::Succeeded, 1, true);
		let mut retry1 = Retry::new(child1);
		let mut status1 = Status::Running;
		while status1 == Status::Running { status1 = retry1.tick(); };
		drop(retry1);
		assert_eq!(status1, Status::Succeeded);

		// No good way to test infinite retrying, so use a limited number
		let child2 = CountedTick::new(Status::Failed, 5, true);
		let mut retry2 = Retry::with_limit(child2, 5);
		let mut status2 = Status::Running;
		for _ in 0..5 { status2 = retry2.tick(); }
		drop(retry2);
		assert_eq!(status2, Status::Failed);
	}
}