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