Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(167)

Side by Side Diff: mojo/public/python/mojo_bindings/promise.py

Issue 2250183003: Make the fuchsia mojo/public repo the source of truth. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 # Copyright 2014 The Chromium 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 """
6 Promise used by the python bindings.
7
8 The API is following the ECMAScript 6 API for promises.
9 """
10
11 import sys
12
13
14 class Promise(object):
15 """The promise object."""
16
17 STATE_PENDING = 0
18 STATE_FULLFILLED = 1
19 STATE_REJECTED = 2
20 STATE_BOUND = 3
21
22 def __init__(self, generator_function):
23 """
24 Constructor.
25
26 Args:
27 generator_function: A function taking 2 arguments: resolve and reject.
28 When |resolve| is called, the promise is fullfilled with the given value.
29 When |reject| is called, the promise is rejected with the given value.
30 A promise can only be resolved or rejected once, all following calls will
31 have no effect.
32 """
33 self._onCatched = []
34 self._onFulfilled = []
35 self._onRejected = []
36 self._state = Promise.STATE_PENDING
37 self._result = None
38 try:
39 generator_function(self._Resolve, self._Reject)
40 except Exception as e:
41 # Adding traceback similarly to python 3.0 (pep-3134)
42 e.__traceback__ = sys.exc_info()[2]
43 self._Reject(e)
44
45 @staticmethod
46 def Resolve(value):
47 """
48 If value is a promise, make a promise that have the same behavior as value,
49 otherwise make a promise that fulfills to value.
50 """
51 if isinstance(value, Promise):
52 return value
53 return Promise(lambda x, y: x(value))
54
55 @staticmethod
56 def Reject(reason):
57 "Make a promise that rejects to reason."""
58 return Promise(lambda x, y: y(reason))
59
60 @staticmethod
61 def All(*iterable):
62 """
63 Make a promise that fulfills when every item in the array fulfills, and
64 rejects if (and when) any item rejects. Each array item is passed to
65 Promise.resolve, so the array can be a mixture of promise-like objects and
66 other objects. The fulfillment value is an array (in order) of fulfillment
67 values. The rejection value is the first rejection value.
68 """
69 def GeneratorFunction(resolve, reject):
70 state = {
71 'rejected': False,
72 'nb_resolved': 0,
73 }
74 promises = [Promise.Resolve(x) for x in iterable]
75 results = [None for x in promises]
76 def OnFullfilled(i):
77 def OnFullfilled(res):
78 if state['rejected']:
79 return
80 results[i] = res
81 state['nb_resolved'] = state['nb_resolved'] + 1
82 if state['nb_resolved'] == len(results):
83 resolve(results)
84 return OnFullfilled
85 def OnRejected(reason):
86 if state['rejected']:
87 return
88 state['rejected'] = True
89 reject(reason)
90
91 for (i, promise) in enumerate(promises):
92 promise.Then(OnFullfilled(i), OnRejected)
93 return Promise(GeneratorFunction)
94
95 @staticmethod
96 def Race(*iterable):
97 """
98 Make a Promise that fulfills as soon as any item fulfills, or rejects as
99 soon as any item rejects, whichever happens first.
100 """
101 def GeneratorFunction(resolve, reject):
102 state = {
103 'ended': False
104 }
105 def OnEvent(callback):
106 def OnEvent(res):
107 if state['ended']:
108 return
109 state['ended'] = True
110 callback(res)
111 return OnEvent
112 for promise in [Promise.Resolve(x) for x in iterable]:
113 promise.Then(OnEvent(resolve), OnEvent(reject))
114 return Promise(GeneratorFunction)
115
116 @property
117 def state(self):
118 if isinstance(self._result, Promise):
119 return self._result.state
120 return self._state
121
122 def Then(self, onFullfilled=None, onRejected=None):
123 """
124 onFulfilled is called when/if this promise resolves. onRejected is called
125 when/if this promise rejects. Both are optional, if either/both are omitted
126 the next onFulfilled/onRejected in the chain is called. Both callbacks have
127 a single parameter, the fulfillment value or rejection reason. |Then|
128 returns a new promise equivalent to the value you return from
129 onFulfilled/onRejected after being passed through Resolve. If an
130 error is thrown in the callback, the returned promise rejects with that
131 error.
132 """
133 if isinstance(self._result, Promise):
134 return self._result.Then(onFullfilled, onRejected)
135 def GeneratorFunction(resolve, reject):
136 recover = reject
137 if onRejected:
138 recover = resolve
139 if self._state == Promise.STATE_PENDING:
140 self._onFulfilled.append(_Delegate(resolve, reject, onFullfilled))
141 self._onRejected.append(_Delegate(recover, reject, onRejected))
142 if self._state == self.STATE_FULLFILLED:
143 _Delegate(resolve, reject, onFullfilled)(self._result)
144 if self._state == self.STATE_REJECTED:
145 _Delegate(recover, reject, onRejected)(self._result)
146 return Promise(GeneratorFunction)
147
148 def Catch(self, onCatched):
149 """Equivalent to |Then(None, onCatched)|"""
150 return self.Then(None, onCatched)
151
152 def __getattr__(self, attribute):
153 """
154 Allows to get member of a promise. It will return a promise that will
155 resolve to the member of the result.
156 """
157 return self.Then(lambda v: getattr(v, attribute))
158
159 def __call__(self, *args, **kwargs):
160 """
161 Allows to call this promise. It will return a promise that will resolved to
162 the result of calling the result of this promise with the given arguments.
163 """
164 return self.Then(lambda v: v(*args, **kwargs))
165
166
167 def _Resolve(self, value):
168 if self.state != Promise.STATE_PENDING:
169 return
170 self._result = value
171 if isinstance(value, Promise):
172 self._state = Promise.STATE_BOUND
173 self._result.Then(_IterateAction(self._onFulfilled),
174 _IterateAction(self._onRejected))
175 return
176 self._state = Promise.STATE_FULLFILLED
177 for f in self._onFulfilled:
178 f(value)
179 self._onFulfilled = None
180 self._onRejected = None
181
182 def _Reject(self, reason):
183 if self.state != Promise.STATE_PENDING:
184 return
185 self._result = reason
186 self._state = Promise.STATE_REJECTED
187 for f in self._onRejected:
188 f(reason)
189 self._onFulfilled = None
190 self._onRejected = None
191
192
193 def async(f):
194 def _ResolvePromises(*args, **kwargs):
195 keys = kwargs.keys()
196 values = kwargs.values()
197 all_args = list(args) + values
198 return Promise.All(*all_args).Then(
199 lambda r: f(*r[:len(args)], **dict(zip(keys, r[len(args):]))))
200 return _ResolvePromises
201
202
203 def _IterateAction(iterable):
204 def _Run(x):
205 for f in iterable:
206 f(x)
207 return _Run
208
209
210 def _Delegate(resolve, reject, action):
211 def _Run(x):
212 try:
213 if action:
214 resolve(action(x))
215 else:
216 resolve(x)
217 except Exception as e:
218 # Adding traceback similarly to python 3.0 (pep-3134)
219 e.__traceback__ = sys.exc_info()[2]
220 reject(e)
221 return _Run
OLDNEW
« no previous file with comments | « mojo/public/python/mojo_bindings/messaging.py ('k') | mojo/public/python/mojo_bindings/reflection.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698