eceadced4425020956caa0f74ed41b0066701aaa
[WebKit-https.git] / Source / JavaScriptCore / builtins / AsyncFromSyncIteratorPrototype.js
1 /*
2  * Copyright (C) 2017 Oleksandr Skachkov <gskachkov@gmail.com>.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 function next(value)
27 {
28     "use strict";
29
30     const promiseCapability = @newPromiseCapability(@Promise);
31
32     if (!@isObject(this) || !@isObject(this.@syncIterator)) {
33         promiseCapability.@reject.@call(@undefined, new @TypeError('Iterator is not an object.'));
34         return promiseCapability.@promise;
35     }
36
37     const syncIterator = this.@syncIterator;
38
39     try {
40         const { done: nextDone, value: nextValue } = syncIterator.next(value);
41         const valueWrapperCapability = @newPromiseCapability(@Promise);
42         valueWrapperCapability.@resolve.@call(@undefined, nextValue);
43         valueWrapperCapability.@promise.@then(
44             function (result) { promiseCapability.@resolve.@call(@undefined, { done: !!nextDone, value: result }); },
45             function (error) { promiseCapability.@reject.@call(@undefined, error); });
46      } catch(e) {
47          promiseCapability.@reject.@call(@undefined, e);
48      }
49
50     return promiseCapability.@promise;
51 }
52
53 function return(value)
54 {
55     "use strict";
56
57     const promiseCapability = @newPromiseCapability(@Promise);
58
59     if (!@isObject(this) || !@isObject(this.@syncIterator)) {
60         promiseCapability.@reject.@call(@undefined, new @TypeError('Iterator is not an object.'));
61         return promiseCapability.@promise;
62     }
63
64     const syncIterator = this.@syncIterator;
65
66     let returnMethod;
67
68     try {
69         returnMethod = syncIterator.return;
70     } catch (e) {
71         promiseCapability.@reject.@call(@undefined, e);
72         return promiseCapability.@promise;
73     }
74
75     if (returnMethod === @undefined) {
76         promiseCapability.@resolve.@call(@undefined, { value, done: true });
77         return promiseCapability.@promise;
78     }
79     
80     try {
81         const returnResult = returnMethod.@call(syncIterator, value);
82
83         if (!@isObject(returnResult)) {
84             promiseCapability.@reject.@call(@undefined, new @TypeError('Iterator result interface is not an object.'));
85             return promiseCapability.@promise;
86         }
87
88         const { done: resultDone, value: resultValue } = returnResult;
89         const valueWrapperCapability = @newPromiseCapability(@Promise);
90
91         valueWrapperCapability.@resolve.@call(@undefined, resultValue);
92         valueWrapperCapability.@promise.@then(
93             function (result) { promiseCapability.@resolve.@call(@undefined, { done: resultDone, value: result }); },
94             function (error) { promiseCapability.@reject.@call(@undefined, error); });
95     } catch (e) {
96         promiseCapability.@reject.@call(@undefined, e);
97     }
98
99     return promiseCapability.@promise;
100 }
101
102 function throw(exception)
103 {
104     "use strict";
105
106     const promiseCapability = @newPromiseCapability(@Promise);
107
108     if (!@isObject(this) || !@isObject(this.@syncIterator)) {
109         promiseCapability.@reject.@call(@undefined, new @TypeError('Iterator is not an object.'));
110         return promiseCapability.@promise;
111     }
112
113     const syncIterator = this.@syncIterator;
114
115     let throwMethod;
116
117     try {
118         throwMethod = syncIterator.throw;
119     } catch (e) {
120         promiseCapability.@reject.@call(@undefined, e);
121         return promiseCapability.@promise;
122     }
123
124     if (throwMethod === @undefined) {
125         promiseCapability.@reject.@call(@undefined, exception);
126         return promiseCapability.@promise;
127     }
128     
129     try {
130         const throwResult = throwMethod.@call(syncIterator, exception);
131         
132         if (!@isObject(throwResult)) {
133             promiseCapability.@reject.@call(@undefined, new @TypeError('Iterator result interface is not an object.'));
134             return promiseCapability.@promise;
135         }
136         
137         const { done: throwDone, value: throwValue } = throwResult;
138         const valueWrapperCapability = @newPromiseCapability(@Promise);
139         
140         valueWrapperCapability.@resolve.@call(@undefined, throwValue);
141         valueWrapperCapability.@promise.@then(
142             function (result) { promiseCapability.@resolve.@call(@undefined, { done: throwDone, value: result }); },
143             function (error) { promiseCapability.@reject.@call(@undefined, error); });
144     } catch (e) {
145         promiseCapability.@reject.@call(@undefined, e);
146     }
147     
148     return promiseCapability.@promise;
149 }
150
151 @globalPrivate
152 function createAsyncFromSyncIterator(syncIterator)
153 {
154     if (!@isObject(syncIterator))
155         @throwTypeError('Only objects can be wrapped by async-from-sync wrapper');
156
157     return new @AsyncFromSyncIteratorConstructor(syncIterator)
158 }
159
160 @globalPrivate
161 @constructor
162 function AsyncFromSyncIteratorConstructor(syncIterator) {
163     this.@syncIterator = syncIterator;
164 }