es6.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // Copyright 2017 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Shims between goog.iter.Iterator and ES6 iterator.
  16. */
  17. goog.module('goog.iter.es6');
  18. const GoogIterable = goog.require('goog.iter.Iterable');
  19. const GoogIterator = goog.require('goog.iter.Iterator');
  20. const StopIteration = goog.require('goog.iter.StopIteration');
  21. /**
  22. * Common interface extending both `goog.iter.Iterable` and ES6 `Iterable`,
  23. * and providing `toGoog()` and `toEs6()` methods to get either kind
  24. * of iterator. `ShimIterable.of()` is the primary entry point for
  25. * this library. If it is given an iterable that is *not* also an
  26. * iterator, then it will inherit any reusability from its argument
  27. * (i.e. `ShimIterable.of(mySet)` will be reusable, since mySet makes
  28. * a fresh Iterator every time, whereas `ShimIterable.of(myIterator)`
  29. * will be one-shot).
  30. *
  31. * `ShimGoogIterator` and `ShimEs6Iterator` extend `ShimIterable` and
  32. * also implement one or the other iterator API. Since they extend
  33. * `ShimIterable`, it is easy to convert back and forth between the two
  34. * APIs. Any such conversion will expose a view to the same underlying
  35. * iterator, so elements pulled via one API will not be available from
  36. * the other.
  37. *
  38. * @interface
  39. * @extends {Iterable<VALUE>}
  40. * @template VALUE
  41. */
  42. class ShimIterable {
  43. /** @return {!GoogIterator<VALUE>} */
  44. __iterator__() {}
  45. /** @return {!ShimGoogIterator<VALUE>} */
  46. toGoog() {}
  47. /** @return {!ShimEs6Iterator<VALUE>} */
  48. toEs6() {}
  49. /**
  50. * @param {!Iterable<VALUE>|!Iterator<VALUE>|
  51. * !GoogIterator<VALUE>|!GoogIterable} iter
  52. * @return {!ShimIterable}
  53. * @template VALUE
  54. */
  55. static of(iter) {
  56. if (iter instanceof ShimIterableImpl || iter instanceof ShimGoogIterator ||
  57. iter instanceof ShimEs6Iterator) {
  58. return iter;
  59. } else if (typeof iter.next == 'function') {
  60. return new ShimIterableImpl(
  61. () => wrapGoog(/** @type {!Iterator|!GoogIterator} */ (iter)));
  62. } else if (typeof iter[Symbol.iterator] == 'function') {
  63. return new ShimIterableImpl(() => iter[Symbol.iterator]());
  64. } else if (typeof iter.__iterator__ == 'function') {
  65. return new ShimIterableImpl(() => wrapGoog(iter.__iterator__()));
  66. }
  67. throw new Error('Not an iterator or iterable.');
  68. }
  69. }
  70. /**
  71. * @param {!GoogIterator<VALUE>|!Iterator<VALUE>} iter
  72. * @return {!Iterator<VALUE>}
  73. * @template VALUE
  74. */
  75. const wrapGoog = (iter) => {
  76. if (!(iter instanceof GoogIterator)) return iter;
  77. let done = false;
  78. return /** @type {?} */ ({
  79. next() {
  80. let value;
  81. while (!done) {
  82. try {
  83. value = iter.next();
  84. break;
  85. } catch (err) {
  86. if (err !== StopIteration) throw err;
  87. done = true;
  88. }
  89. }
  90. return {value, done};
  91. },
  92. });
  93. };
  94. /**
  95. * Concrete (private) implementation of a non-iterator iterable. This is
  96. * separate from the iterator versions since it supports iterables that
  97. * are not "one-shot".
  98. * @implements {ShimIterable<VALUE>}
  99. * @template VALUE
  100. */
  101. class ShimIterableImpl {
  102. /** @param {function(): !Iterator<VALUE>} func */
  103. constructor(func) {
  104. /** @const @private */
  105. this.func_ = func;
  106. }
  107. /** @override */
  108. __iterator__() {
  109. return new ShimGoogIterator(this.func_());
  110. }
  111. /** @override */
  112. toGoog() {
  113. return new ShimGoogIterator(this.func_());
  114. }
  115. /** @override */
  116. [Symbol.iterator]() {
  117. return new ShimEs6Iterator(this.func_());
  118. }
  119. /** @override */
  120. toEs6() {
  121. return new ShimEs6Iterator(this.func_());
  122. }
  123. }
  124. /**
  125. * Concrete `goog.iter.Iterator` subclass that also implements `ShimIterable`.
  126. * @extends {GoogIterator<VALUE>}
  127. * @implements {ShimIterable<VALUE>}
  128. * @template VALUE
  129. */
  130. class ShimGoogIterator extends GoogIterator {
  131. /** @param {!Iterator<VALUE>} iter */
  132. constructor(iter) {
  133. super();
  134. this.iter_ = iter;
  135. }
  136. /** @override */
  137. __iterator__() {
  138. // TODO(user): this seems ridiculous, but the compiler complains
  139. // that it's not implemented if we don't have it.
  140. return super.__iterator__();
  141. }
  142. /** @override */
  143. next() {
  144. const result = this.iter_.next();
  145. if (result.done) throw StopIteration;
  146. return result.value;
  147. }
  148. /** @override */
  149. toGoog() {
  150. return this;
  151. }
  152. /** @override */
  153. [Symbol.iterator]() {
  154. return new ShimEs6Iterator(this.iter_);
  155. }
  156. /** @override */
  157. toEs6() {
  158. return new ShimEs6Iterator(this.iter_);
  159. }
  160. }
  161. /**
  162. * Concrete ES6 `Iterator` that also implements `ShimIterable`.
  163. * @implements {IteratorIterable<VALUE>}
  164. * @extends {ShimIterableImpl<VALUE>}
  165. * @template VALUE
  166. */
  167. class ShimEs6Iterator extends ShimIterableImpl {
  168. /** @param {!Iterator<VALUE>} iter */
  169. constructor(iter) {
  170. super(() => iter);
  171. /** @const @private */
  172. this.iter_ = iter;
  173. }
  174. /** @override */
  175. next() {
  176. return this.iter_.next();
  177. }
  178. }
  179. exports = {
  180. ShimIterable,
  181. ShimEs6Iterator,
  182. ShimGoogIterator,
  183. };