1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "promise_example1.h"
6 
7 #include <string>
8 
9 #include <lib/fit/promise.h>
10 #include <lib/fit/single_threaded_executor.h>
11 
12 #include "utils.h"
13 
14 // This example demonstrates sequencing of tasks using combinators.
15 namespace promise_example1 {
16 
pick_bananas(int hours)17 fit::promise<int, std::string> pick_bananas(int hours) {
18     return fit::make_promise([hours, time = 0, harvest = 0](fit::context& context) mutable
19                              -> fit::result<int, std::string> {
20         if (time == 0) {
21             printf("Starting the day picking bananas for %d hours...\n", hours);
22         } else {
23             printf("... %d hour elapsed...\n", time);
24         }
25         if (random() % 7 == 0) {
26             return fit::error("A wild animal ate all the bananas we picked today!");
27         }
28         if (time < hours) {
29             // Simulate time passing.
30             // Here we call |suspend_task()| to obtain a |fit::suspended_task|
31             // which acts as a handle which will later be used by
32             // |resume_in_a_little_while()| to resume the task.  In the
33             // meantime, we unwind the call stack by returning |fit::pending()|.
34             // Once the task is resumed, the promise's handler will restart
35             // execution from the top again, however it will have retained
36             // state (in |time| and |harvest|) from its prior execution.
37             utils::resume_in_a_little_while(context.suspend_task());
38             time++;
39             harvest += random() % 31;
40             return fit::pending();
41         }
42         return fit::ok(harvest);
43     });
44 }
45 
eat_bananas(int appetite)46 fit::promise<void, std::string> eat_bananas(int appetite) {
47     return fit::make_promise([appetite](fit::context& context) mutable
48                              -> fit::result<void, std::string> {
49         if (appetite > 0) {
50             printf("... eating a yummy banana....\n");
51             utils::resume_in_a_little_while(context.suspend_task());
52             appetite--;
53             if (random() % 11 == 0) {
54                 return fit::error("I ate too many bananas.  Urp.");
55             }
56             return fit::pending();
57         }
58         puts("Ahh.  So satisfying.");
59         return fit::ok();
60     });
61 }
62 
prepare_simulation()63 fit::promise<> prepare_simulation() {
64     int hours = random() % 8;
65     return pick_bananas(hours)
66         .and_then([](int harvest) -> fit::result<int, std::string> {
67             printf("We picked %d bananas today!\n", harvest);
68             if (harvest == 0)
69                 return fit::error("What will we eat now?");
70             return fit::ok(harvest);
71         })
72         .and_then([](int harvest) {
73             int appetite = random() % 7;
74             if (appetite > harvest)
75                 appetite = harvest;
76             return eat_bananas(appetite);
77         })
78         .or_else([](std::string error) {
79             printf("Oh no!  %s\n", error.c_str());
80             return fit::error();
81         })
82         .and_then([] {
83             puts("*** Simulation finished ***");
84         })
85         .or_else([] {
86             puts("*** Restarting simulation ***");
87             return prepare_simulation();
88         });
89 }
90 
run()91 void run() {
92     auto simulation = prepare_simulation();
93     fit::run_single_threaded(std::move(simulation));
94 }
95 
96 } // namespace promise_example1
97