- In the src/bin folder, create a file called returning.rs.
- Add the following code and run it with cargo run —bin returning:
1 extern crate futures; 2 3 use futures::executor::block_on; 4 use futures::future::{join_all, Future, FutureResult, ok}; 5 use futures::prelude::*; 6 7 #[derive(Clone, Copy, Debug, PartialEq)] 8 enum PlayerStatus { 9 Loading, 10 Default, 11 Jumping, 12 } 13 14 #[derive(Clone, Copy, Debug)] 15 struct Player { 16 name: &'static str, 17 status: PlayerStatus, 18 score: u32, 19 ticks: usize, 20 }
- Now comes the implementations for the structs:
22 impl Player { 23 fn new(name: &'static str) -> Self { 24 let mut ticks = 1; 25 // Give Bob more ticks explicitly 26 if name == "Bob" { 27 ticks = 5; 28 } 29 30 Player { 31 name: name, 32 status: PlayerStatus::Loading, 33 score: 0, 34 ticks: ticks, 35 } 36 } 37 38 fn set_status(&mut self, status: PlayerStatus) ->
FutureResult<&mut Self, Never> { 39 self.status = status; 40 ok(self) 41 } 42 43 fn can_add_points(&mut self) -> bool { 44 if self.status == PlayerStatus::Default { 45 return true; 46 } 47 48 println!("We couldn't add any points for {}!", self.name); 49 return false; 50 } 51 52 fn add_points(&mut self, points: u32) -> Async<&mut Self> { 53 if !self.can_add_points() { 54 Async::Ready(self) 55 } else { 56 let new_score = self.score + points; 57 // Here we would send the new score to a remote server 58 // but for now we will manaully increment the player's
score. 59 60 self.score = new_score; 61 62 Async::Ready(self) 63 } 64 } 65 } 66 67 impl Future for Player { 68 type Item = Player; 69 type Error = (); 70 71 fn poll(&mut self, cx: &mut task::Context) ->
Poll<Self::Item, Self::Error> { 72 // Presuming we fetch our player's score from a 73 // server upon initial load. 74 // After we perform the fetch send the Result value. 75 76 println!("Player {} has been poll'ed!", self.name); 77 78 if self.ticks == 0 { 79 self.status = PlayerStatus::Default; 80 Ok(Async::Ready(*self)) 81 } else { 82 self.ticks -= 1; 83 cx.waker().wake(); 84 Ok(Async::Pending) 85 } 86 } 87 }
- Next, we'll want to add our helper functions and our Async function for adding points to our players:
89 fn async_add_points(player: &mut Player, 90 points: u32) 91 -> Box<Future + Send> { 92 // Presuming that player.add_points() will send the points to a 93 // database/server over a network and returns an updated 94 // player score from the server/database. 95 let _ = player.add_points(points); 96 97 // Additionally, we may want to add logging mechanisms, 98 // friend notifications, etc. here. 99 100 return Box::new(ok(*player)); 101 } 102 103 fn display_scoreboard(players: Vec<&Player>) { 104 for player in players { 105 println!("{}'s Score: {}", player.name, player.score); 106 } 107 }
- And finally, the actual usage:
109 fn main() { 110 let mut player1 = Player::new("Bob"); 111 let mut player2 = Player::new("Alice"); 112 113 let tasks = join_all(vec![player1, player2]); 114 115 let f = join_all(vec![ 116 async_add_points(&mut player1, 5), 117 async_add_points(&mut player2, 2), 118 ]) 119 .then(|x| { 120 println!("First batch of adding points is done."); 121 x 122 }); 123 124 block_on(f).unwrap(); 125 126 let players = block_on(tasks).unwrap(); 127 player1 = players[0]; 128 player2 = players[1]; 129 130 println!("Scores should be zero since no players were
loaded"); 131 display_scoreboard(vec![&player1, &player2]); 132 133 // In our minigame, a player cannot score if they are
currently 134 // in the air or "jumping." 135 // Let's make one of our players' status set to the jumping
status. 136 137 let f =
player2.set_status(PlayerStatus::Jumping).and_then(move |mut
new_player2| { 138 async_add_points(&mut player1, 10) 139 .and_then(move |_| { 140 println!("Finished trying to give Player 1 points."); 141 async_add_points(&mut new_player2, 2) 142 }) 143 .then(move |new_player2| { 144 println!("Finished trying to give Player 2 points."); 145 println!("Player 1 (Bob) should have a score of 10 and
Player 2 (Alice) should 146 have a score of 0"); 147 148 // unwrap is used here to since 149 display_scoreboard(vec![&player1,
&new_player2.unwrap()]); 150 new_player2 151 }) 152 }); 153 154 block_on(f).unwrap(); 155 156 println!("All done!"); 157 }