tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

padding-iteration.js (3946B)


      1 // Copyright (C) 2025 André Bargull. All rights reserved.
      2 // This code is governed by the BSD license found in the LICENSE file.
      3 
      4 /*---
      5 esid: sec-iterator.zip
      6 description: >
      7  Perform iteration of the "padding" option.
      8 info: |
      9  Iterator.zip ( iterables [ , options ] )
     10    ...
     11    14. If mode is "longest", then
     12      ...
     13      b. Else,
     14        i. Let paddingIter be Completion(GetIterator(paddingOption, sync)).
     15        ...
     16        iii. Let usingIterator be true.
     17        iv. Perform the following steps iterCount times:
     18          1. If usingIterator is true, then
     19            a. Set next to Completion(IteratorStepValue(paddingIter)).
     20            ...
     21            c. If next is done, then
     22              i. Set usingIterator to false.
     23            d. Else,
     24              i. Append next to padding.
     25          2. If usingIterator is false, append undefined to padding.
     26            v. If usingIterator is true, then
     27              1. Let completion be Completion(IteratorClose(paddingIter, NormalCompletion(unused))).
     28              ...
     29    ...
     30 
     31  GetIterator ( obj, kind )
     32    ...
     33    2. Else,
     34      a. Let method be ? GetMethod(obj, %Symbol.iterator%).
     35    3. If method is undefined, throw a TypeError exception.
     36    4. Return ? GetIteratorFromMethod(obj, method).
     37 
     38  GetIteratorFromMethod ( obj, method )
     39    1. Let iterator be ? Call(method, obj).
     40    2. If iterator is not an Object, throw a TypeError exception.
     41    3. Return ? GetIteratorDirect(iterator).
     42 
     43  GetIteratorDirect ( obj )
     44    1. Let nextMethod be ? Get(obj, "next").
     45    2. Let iteratorRecord be the Iterator Record { [[Iterator]]: obj, [[NextMethod]]: nextMethod, [[Done]]: false }.
     46    3. Return iteratorRecord.
     47 includes: [proxyTrapsHelper.js, compareArray.js]
     48 features: [joint-iteration]
     49 ---*/
     50 
     51 function makeProxyWithGetHandler(log, name, obj) {
     52  return new Proxy(obj, allowProxyTraps({
     53    get(target, propertyKey, receiver) {
     54      log.push(`${name}::${String(propertyKey)}`);
     55      return Reflect.get(target, propertyKey, receiver);
     56    }
     57  }));
     58 }
     59 
     60 // "padding" option must be an iterable.
     61 assert.throws(TypeError, function() {
     62  Iterator.zip([], {
     63    mode: "longest",
     64    padding: {},
     65  });
     66 });
     67 
     68 for (var n = 0; n <= 5; ++n) {
     69  var iterables = Array(n).fill([]);
     70 
     71  for (var k = 0; k <= n + 2; ++k) {
     72    var elements = Array(k).fill(0);
     73    var elementsIter = elements.values();
     74 
     75    var log = [];
     76 
     77    var padding = makeProxyWithGetHandler(log, "padding", {
     78      [Symbol.iterator]() {
     79        log.push("call iterator");
     80 
     81        // Called with the correct receiver and no arguments.
     82        assert.sameValue(this, padding);
     83        assert.sameValue(arguments.length, 0);
     84 
     85        return this;
     86      },
     87      next() {
     88        log.push("call next");
     89 
     90        // Called with the correct receiver and no arguments.
     91        assert.sameValue(this, padding);
     92        assert.sameValue(arguments.length, 0);
     93 
     94        return elementsIter.next();
     95      },
     96      return() {
     97        log.push("call return");
     98 
     99        // Called with the correct receiver and no arguments.
    100        assert.sameValue(this, padding);
    101        assert.sameValue(arguments.length, 0);
    102 
    103        return {};
    104      }
    105    });
    106 
    107    Iterator.zip(iterables, {mode: "longest", padding});
    108 
    109    // Property reads and calls from GetIterator.
    110    var expected = [
    111      "padding::Symbol(Symbol.iterator)",
    112      "call iterator",
    113      "padding::next",
    114    ];
    115 
    116    // Call the "next" method |n| times until the padding iterator is exhausted.
    117    for (var i = 0; i < Math.min(n, k); ++i) {
    118      expected.push("call next");
    119    }
    120 
    121    // If |n| is larger than |k|, then there was one final call to the "next"
    122    // method. Otherwise the "return" method was called to close the padding
    123    // iterator.
    124    if (n > k) {
    125      expected.push("call next");
    126    } else {
    127      expected.push(
    128        "padding::return",
    129        "call return"
    130      );
    131    }
    132 
    133    assert.compareArray(log, expected);
    134  }
    135 }
    136 
    137 reportCompare(0, 0);